CELO Price: $0.09 (-3.45%)
Gas: 25 GWei

Contract

0xa4d9c19de4881876B14d3C682f79634e2785b2f7

Overview

CELO Balance

Celo Mainnet LogoCelo Mainnet LogoCelo Mainnet Logo0 CELO

CELO Value

$0.00

More Info

Private Name Tags

Multichain Info

Transaction Hash
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ManifestoCensus

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 200 runs

Other Settings:
prague EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {CircularBuffer} from "openzeppelin-contracts/contracts/utils/structs/CircularBuffer.sol";
import {InternalLeanIMT, LeanIMTData} from "zk-kit.solidity/packages/lean-imt/contracts/InternalLeanIMT.sol";
import {SNARK_SCALAR_FIELD} from "zk-kit.solidity/packages/lean-imt/contracts/Constants.sol";
import {ICensusValidator} from "./ICensusValidator.sol";
import {SelfVerificationRoot} from "@selfxyz/contracts/contracts/abstract/SelfVerificationRoot.sol";
import {ISelfVerificationRoot} from "@selfxyz/contracts/contracts/interfaces/ISelfVerificationRoot.sol";
import {SelfStructs} from "@selfxyz/contracts/contracts/libraries/SelfStructs.sol";
import {SelfUtils} from "@selfxyz/contracts/contracts/libraries/SelfUtils.sol";
import {IIdentityVerificationHubV2} from "@selfxyz/contracts/contracts/interfaces/IIdentityVerificationHubV2.sol";

/// @title Manifesto Census Contract
/// @notice Self-gated registry of addresses that have pledged to the manifesto
/// @dev Verification is enforced through the Self IdentityVerificationHub V2 contracts on Celo
contract ManifestoCensus is ICensusValidator, SelfVerificationRoot {
    using InternalLeanIMT for LeanIMTData;
    using CircularBuffer for CircularBuffer.Bytes32CircularBuffer;

    // ========= Manifesto Metadata =========

    struct ManifestoMetadata {
        string title;
        string authors;
        string date;
        string manifestoText;
    }

    string public TITLE;
    string public AUTHORS;
    string public DATE;
    string public MANIFESTO;

    // ========= State Variables =========

    /// @notice Timestamp when an address pledged (0 = never pledged)
    mapping(address => uint256) public pledgeTimestamp;

    /// @notice Total number of pledges
    uint256 public pledgeCount;

    /// @notice Census Merkle tree (Lean-IMT)
    LeanIMTData private _census;

    /// @notice Root history (circular buffer + mapping for O(1) lookup)
    CircularBuffer.Bytes32CircularBuffer private _rootBuffer;
    mapping(bytes32 => uint64) private _rootToBlock;

    /// @notice Verification configuration stored on-chain for transparency
    SelfStructs.VerificationConfigV2 public verificationConfig;

    /// @notice Config identifier registered in the Self hub
    bytes32 public verificationConfigId;

    /// @notice Tracks used nullifiers to guard against replay attempts
    mapping(uint256 => bool) public nullifierUsed;

    /// @notice Allowed document types (attestation identifiers)
    mapping(bytes32 => bool) public allowedAttestation;
    bytes32[] private _attestationAllowListValues;

    /// @notice Stores forbidden country codes for inspection
    string[] private _forbiddenCountries;

    /// @notice Human-readable scope string used during deployment
    string public scopeLabel;

    /// @notice Optional nationality restriction (ISO Alpha-3 uppercase)
    bytes3 public requiredNationality;

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

    event Pledged(address indexed signer, uint256 timestamp);
    event CensusRootUpdated(uint256 indexed newRoot, uint256 blockNumber);
    event IdentityVerified(address indexed signer, uint256 nullifier, bytes32 attestationId);

    // ========= Custom Errors =========

    error AlreadyPledged();
    error NullifierAlreadyUsed();
    error InvalidSigner();
    error UnsupportedAttestation(bytes32 attestationId);
    error SelfVerificationOnly();
    error NationalityMismatch(bytes3 required, bytes3 provided);
    error InvalidNationalityString();
    error NoAttestationTypesProvided();

    // ========= Constructor =========

    /**
     * @param identityVerificationHubV2Address Address of the Self IdentityVerificationHub V2
     * @param scopeSeed Scope seed used to derive the scope inside SelfVerificationRoot
     * @param unformattedVerificationConfig Unformatted verification config (min age, forbidden countries, ofac)
     * @param attestationAllowList List of allowed attestation IDs (document types)
     */
    constructor(
        address identityVerificationHubV2Address,
        string memory scopeSeed,
        SelfUtils.UnformattedVerificationConfigV2 memory unformattedVerificationConfig,
        bytes32[] memory attestationAllowList,
        string memory requiredNationalityInput,
        ManifestoMetadata memory metadata
    ) SelfVerificationRoot(identityVerificationHubV2Address, scopeSeed) {
        if (attestationAllowList.length == 0) {
            revert NoAttestationTypesProvided();
        }

        // Initialize circular buffer with capacity for 100 recent roots
        _rootBuffer.setup(100);

        scopeLabel = scopeSeed;
        verificationConfig = SelfUtils.formatVerificationConfigV2(unformattedVerificationConfig);
        verificationConfigId = IIdentityVerificationHubV2(identityVerificationHubV2Address).setVerificationConfigV2(
            verificationConfig
        );

        for (uint256 i = 0; i < attestationAllowList.length; i++) {
            bytes32 attestationId = attestationAllowList[i];
            allowedAttestation[attestationId] = true;
            _attestationAllowListValues.push(attestationId);
        }

        if (unformattedVerificationConfig.forbiddenCountries.length > 0) {
            for (uint256 i = 0; i < unformattedVerificationConfig.forbiddenCountries.length; i++) {
                _forbiddenCountries.push(unformattedVerificationConfig.forbiddenCountries[i]);
            }
        }

        if (bytes(requiredNationalityInput).length == 0) {
            requiredNationality = bytes3(0);
        } else {
            requiredNationality = _normalizeCountryCode(requiredNationalityInput);
        }

        TITLE = metadata.title;
        AUTHORS = metadata.authors;
        DATE = metadata.date;
        MANIFESTO = metadata.manifestoText;
    }

    // ========= Public Functions =========

    /// @notice External pledge function is disabled; all pledges must go through Self verification
    function pledge() external pure {
        revert SelfVerificationOnly();
    }

    // ========= View Functions =========

    /// @notice Check if an address has pledged
    /// @param who Address to check
    /// @return True if the address has pledged
    function hasPledged(address who) external view returns (bool) {
        return pledgeTimestamp[who] != 0;
    }

    /// @notice Check if an address pledged before a specific timestamp
    /// @param who Address to check
    /// @param cutoff Unix timestamp cutoff
    /// @return True if the address pledged on or before the cutoff
    function pledgedBefore(address who, uint256 cutoff) external view returns (bool) {
        uint256 ts = pledgeTimestamp[who];
        return ts != 0 && ts <= cutoff;
    }

    /// @notice Get the current census Merkle root
    /// @return Current Merkle root
    function getCensusRoot() external view returns (uint256) {
        return _census._root();
    }

    /// @notice Validates a census root and returns the block number when it was set
    /// @dev Implements ICensusValidator interface
    /// @param root The census Merkle root to validate
    /// @return blockNumber The block number when this root was set (0 if invalid/evicted)
    function getRootBlockNumber(uint256 root) external view returns (uint256 blockNumber) {
        return uint256(_rootToBlock[bytes32(root)]);
    }

    /// @notice Compute the packed leaf value for an address
    /// @dev Helper function for off-chain proof generation and verification
    ///      Leaf format: (address << 88) | weight, where weight = 1
    /// @param account The address to compute the leaf for
    /// @return The packed leaf value
    function computeLeaf(address account) external pure returns (uint256) {
        return (uint256(uint160(account)) << 88) | 1;
    }

    /// @notice View helper exposing whether an attestation ID is allowed
    function isAttestationAllowed(bytes32 attestationId) external view returns (bool) {
        return allowedAttestation[attestationId];
    }

    /// @notice Returns the complete attestation allow list for off-chain consumers
    function getAllowedAttestationIds() external view returns (bytes32[] memory) {
        bytes32[] memory ids = new bytes32[](_attestationAllowListValues.length);
        for (uint256 i = 0; i < _attestationAllowListValues.length; i++) {
            ids[i] = _attestationAllowListValues[i];
        }
        return ids;
    }

    /// @notice Exposes the hub address for off-chain tooling
    function identityVerificationHub() external view returns (address) {
        return address(_identityVerificationHubV2);
    }

    /// @notice Returns the verification rules enforced by this deployment
    function getVerificationParameters()
        external
        view
        returns (
            uint256 minAge,
            bool minAgeEnabled,
            bool ofacEnabled,
            string[] memory forbiddenCountries,
            bytes3 nationality,
            bytes32[] memory attestationTypes
        )
    {
        SelfStructs.VerificationConfigV2 memory config = verificationConfig;
        minAge = config.olderThan;
        minAgeEnabled = config.olderThanEnabled;
        ofacEnabled = config.ofacEnabled[0];
        nationality = requiredNationality;

        forbiddenCountries = new string[](_forbiddenCountries.length);
        for (uint256 i = 0; i < _forbiddenCountries.length; i++) {
            forbiddenCountries[i] = _forbiddenCountries[i];
        }

        attestationTypes = new bytes32[](_attestationAllowListValues.length);
        for (uint256 i = 0; i < _attestationAllowListValues.length; i++) {
            attestationTypes[i] = _attestationAllowListValues[i];
        }
    }

    // ========= Self Integration Overrides =========

    /// @inheritdoc SelfVerificationRoot
    function getConfigId(
        bytes32,
        bytes32,
        bytes memory
    ) public view override returns (bytes32) {
        return verificationConfigId;
    }

    /// @inheritdoc SelfVerificationRoot
    function customVerificationHook(
        ISelfVerificationRoot.GenericDiscloseOutputV2 memory output,
        bytes memory /* userData */
    ) internal override {
        if (!allowedAttestation[output.attestationId]) {
            revert UnsupportedAttestation(output.attestationId);
        }

        uint256 nullifier = output.nullifier;
        if (nullifierUsed[nullifier]) {
            revert NullifierAlreadyUsed();
        }

        address signer = address(uint160(output.userIdentifier));
        if (signer == address(0)) {
            revert InvalidSigner();
        }

        if (requiredNationality != bytes3(0)) {
            bytes3 providedNationality = _normalizeCountryCode(output.nationality);
            if (providedNationality != requiredNationality) {
                revert NationalityMismatch(requiredNationality, providedNationality);
            }
        }

        if (pledgeTimestamp[signer] != 0) {
            revert AlreadyPledged();
        }

        nullifierUsed[nullifier] = true;
        pledgeTimestamp[signer] = block.timestamp;
        pledgeCount++;

        uint256 leaf = (uint256(uint160(signer)) << 88) | 1;
        require(leaf < SNARK_SCALAR_FIELD, "Invalid leaf value");

        _census._insert(leaf);
        _updateRootHistory();

        emit IdentityVerified(signer, nullifier, output.attestationId);
        emit Pledged(signer, block.timestamp);
    }

    // ========= Internal Functions =========

    /// @dev Update root history after tree modification
    function _updateRootHistory() internal {
        uint256 newRoot = _census._root();
        bytes32 newRootBytes = bytes32(newRoot);

        // Push to circular buffer (automatically evicts oldest if full)
        _rootBuffer.push(newRootBytes);
        _rootToBlock[newRootBytes] = uint64(block.number);

        // Note: We accept minor storage leak for evicted roots (they'll remain in mapping)
        // This is negligible compared to the gas cost of tracking and cleaning them

        emit CensusRootUpdated(newRoot, block.number);
    }

    /// @dev Normalizes a 3-letter country code to uppercase bytes3 representation
    function _normalizeCountryCode(string memory code) internal pure returns (bytes3 result) {
        bytes memory raw = bytes(code);
        if (raw.length != 3) revert InvalidNationalityString();

        bytes memory normalized = new bytes(3);
        for (uint256 i = 0; i < 3; i++) {
            uint8 charCode = uint8(raw[i]);
            if (charCode >= 97 && charCode <= 122) {
                charCode -= 32;
            }
            if (charCode < 65 || charCode > 90) revert InvalidNationalityString();
            normalized[i] = bytes1(charCode);
        }

        assembly {
            result := mload(add(normalized, 32))
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/structs/CircularBuffer.sol)
pragma solidity ^0.8.20;

import {Math} from "../math/Math.sol";
import {Arrays} from "../Arrays.sol";
import {Panic} from "../Panic.sol";

/**
 * @dev A fixed-size buffer for keeping `bytes32` items in storage.
 *
 * This data structure allows for pushing elements to it, and when its length exceeds the specified fixed size,
 * new items take the place of the oldest element in the buffer, keeping at most `N` elements in the
 * structure.
 *
 * Elements can't be removed but the data structure can be cleared. See {clear}.
 *
 * Complexity:
 * - insertion ({push}): O(1)
 * - lookup ({last}): O(1)
 * - inclusion ({includes}): O(N) (worst case)
 * - reset ({clear}): O(1)
 *
 * * The struct is called `Bytes32CircularBuffer`. Other types can be cast to and from `bytes32`. This data structure
 * can only be used in storage, and not in memory.
 *
 * Example usage:
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using CircularBuffer for CircularBuffer.Bytes32CircularBuffer;
 *
 *     // Declare a buffer storage variable
 *     CircularBuffer.Bytes32CircularBuffer private myBuffer;
 * }
 * ```
 *
 * _Available since v5.1._
 */
library CircularBuffer {
    /**
     * @dev Error emitted when trying to setup a buffer with a size of 0.
     */
    error InvalidBufferSize();

    /**
     * @dev Counts the number of items that have been pushed to the buffer. The residuo modulo _data.length indicates
     * where the next value should be stored.
     *
     * Struct members have an underscore prefix indicating that they are "private" and should not be read or written to
     * directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and
     * lead to unexpected behavior.
     *
     * In a full buffer:
     * - The most recently pushed item (last) is at data[(index - 1) % data.length]
     * - The oldest item (first) is at data[index % data.length]
     */
    struct Bytes32CircularBuffer {
        uint256 _count;
        bytes32[] _data;
    }

    /**
     * @dev Initialize a new CircularBuffer of a given size.
     *
     * If the CircularBuffer was already setup and used, calling that function again will reset it to a blank state.
     *
     * NOTE: The size of the buffer will affect the execution of {includes} function, as it has a complexity of O(N).
     * Consider a large buffer size may render the function unusable.
     */
    function setup(Bytes32CircularBuffer storage self, uint256 size) internal {
        if (size == 0) revert InvalidBufferSize();
        clear(self);
        Arrays.unsafeSetLength(self._data, size);
    }

    /**
     * @dev Clear all data in the buffer without resetting memory, keeping the existing size.
     */
    function clear(Bytes32CircularBuffer storage self) internal {
        self._count = 0;
    }

    /**
     * @dev Push a new value to the buffer. If the buffer is already full, the new value replaces the oldest value in
     * the buffer.
     */
    function push(Bytes32CircularBuffer storage self, bytes32 value) internal {
        uint256 index = self._count++;
        uint256 modulus = self._data.length;
        Arrays.unsafeAccess(self._data, index % modulus).value = value;
    }

    /**
     * @dev Number of values currently in the buffer. This value is 0 for an empty buffer, and cannot exceed the size of
     * the buffer.
     */
    function count(Bytes32CircularBuffer storage self) internal view returns (uint256) {
        return Math.min(self._count, self._data.length);
    }

    /**
     * @dev Length of the buffer. This is the maximum number of elements kept in the buffer.
     */
    function length(Bytes32CircularBuffer storage self) internal view returns (uint256) {
        return self._data.length;
    }

    /**
     * @dev Getter for the i-th value in the buffer, from the end.
     *
     * Reverts with {Panic-ARRAY_OUT_OF_BOUNDS} if trying to access an element that was not pushed, or that was
     * dropped to make room for newer elements.
     */
    function last(Bytes32CircularBuffer storage self, uint256 i) internal view returns (bytes32) {
        uint256 index = self._count;
        uint256 modulus = self._data.length;
        uint256 total = Math.min(index, modulus); // count(self)
        if (i >= total) {
            Panic.panic(Panic.ARRAY_OUT_OF_BOUNDS);
        }
        return Arrays.unsafeAccess(self._data, (index - i - 1) % modulus).value;
    }

    /**
     * @dev Check if a given value is in the buffer.
     */
    function includes(Bytes32CircularBuffer storage self, bytes32 value) internal view returns (bool) {
        uint256 index = self._count;
        uint256 modulus = self._data.length;
        uint256 total = Math.min(index, modulus); // count(self)
        for (uint256 i = 0; i < total; ++i) {
            if (Arrays.unsafeAccess(self._data, (index - i - 1) % modulus).value == value) {
                return true;
            }
        }
        return false;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import {PoseidonT3} from "poseidon-solidity/PoseidonT3.sol";
import {SNARK_SCALAR_FIELD} from "./Constants.sol";

struct LeanIMTData {
    // Tracks the current number of leaves in the tree.
    uint256 size;
    // Represents the current depth of the tree, which can increase as new leaves are inserted.
    uint256 depth;
    // A mapping from each level of the tree to the node value of the last even position at that level.
    // Used for efficient inserts, updates and root calculations.
    mapping(uint256 => uint256) sideNodes;
    // A mapping from leaf values to their respective indices in the tree.
    // This facilitates checks for leaf existence and retrieval of leaf positions.
    mapping(uint256 => uint256) leaves;
}

error WrongSiblingNodes();
error LeafGreaterThanSnarkScalarField();
error LeafCannotBeZero();
error LeafAlreadyExists();
error LeafDoesNotExist();

/// @title Lean Incremental binary Merkle tree.
/// @dev The LeanIMT is an optimized version of the BinaryIMT.
/// This implementation eliminates the use of zeroes, and make the tree depth dynamic.
/// When a node doesn't have the right child, instead of using a zero hash as in the BinaryIMT,
/// the node's value becomes that of its left child. Furthermore, rather than utilizing a static tree depth,
/// it is updated based on the number of leaves in the tree. This approach
/// results in the calculation of significantly fewer hashes, making the tree more efficient.
library InternalLeanIMT {
    /// @dev Inserts a new leaf into the incremental merkle tree.
    /// The function ensures that the leaf is valid according to the
    /// constraints of the tree and then updates the tree's structure accordingly.
    /// @param self: A storage reference to the 'LeanIMTData' struct.
    /// @param leaf: The value of the new leaf to be inserted into the tree.
    /// @return The new hash of the node after the leaf has been inserted.
    function _insert(LeanIMTData storage self, uint256 leaf) internal returns (uint256) {
        if (leaf >= SNARK_SCALAR_FIELD) {
            revert LeafGreaterThanSnarkScalarField();
        } else if (leaf == 0) {
            revert LeafCannotBeZero();
        } else if (_has(self, leaf)) {
            revert LeafAlreadyExists();
        }

        uint256 index = self.size;

        // Cache tree depth to optimize gas
        uint256 treeDepth = self.depth;

        // A new insertion can increase a tree's depth by at most 1,
        // and only if the number of leaves supported by the current
        // depth is less than the number of leaves to be supported after insertion.
        if (2 ** treeDepth < index + 1) {
            ++treeDepth;
        }

        self.depth = treeDepth;

        uint256 node = leaf;

        for (uint256 level = 0; level < treeDepth; ) {
            if ((index >> level) & 1 == 1) {
                node = PoseidonT3.hash([self.sideNodes[level], node]);
            } else {
                self.sideNodes[level] = node;
            }

            unchecked {
                ++level;
            }
        }

        self.size = ++index;

        self.sideNodes[treeDepth] = node;
        self.leaves[leaf] = index;

        return node;
    }

    /// @dev Inserts many leaves into the incremental merkle tree.
    /// The function ensures that the leaves are valid according to the
    /// constraints of the tree and then updates the tree's structure accordingly.
    /// @param self: A storage reference to the 'LeanIMTData' struct.
    /// @param leaves: The values of the new leaves to be inserted into the tree.
    /// @return The root after the leaves have been inserted.
    function _insertMany(LeanIMTData storage self, uint256[] calldata leaves) internal returns (uint256) {
        // Cache tree size to optimize gas
        uint256 treeSize = self.size;

        // Check that all the new values are correct to be added.
        for (uint256 i = 0; i < leaves.length; ) {
            if (leaves[i] >= SNARK_SCALAR_FIELD) {
                revert LeafGreaterThanSnarkScalarField();
            } else if (leaves[i] == 0) {
                revert LeafCannotBeZero();
            } else if (_has(self, leaves[i])) {
                revert LeafAlreadyExists();
            }

            self.leaves[leaves[i]] = treeSize + 1 + i;

            unchecked {
                ++i;
            }
        }

        // Array to save the nodes that will be used to create the next level of the tree.
        uint256[] memory currentLevelNewNodes;

        currentLevelNewNodes = leaves;

        // Cache tree depth to optimize gas
        uint256 treeDepth = self.depth;

        // Calculate the depth of the tree after adding the new values.
        // Unlike the 'insert' function, we need a while here as
        // N insertions can increase the tree's depth more than once.
        while (2 ** treeDepth < treeSize + leaves.length) {
            ++treeDepth;
        }

        self.depth = treeDepth;

        // First index to change in every level.
        uint256 currentLevelStartIndex = treeSize;

        // Size of the level used to create the next level.
        uint256 currentLevelSize = treeSize + leaves.length;

        // The index where changes begin at the next level.
        uint256 nextLevelStartIndex = currentLevelStartIndex >> 1;

        // The size of the next level.
        uint256 nextLevelSize = ((currentLevelSize - 1) >> 1) + 1;

        for (uint256 level = 0; level < treeDepth; ) {
            // The number of nodes for the new level that will be created,
            // only the new values, not the entire level.
            uint256 numberOfNewNodes = nextLevelSize - nextLevelStartIndex;
            uint256[] memory nextLevelNewNodes = new uint256[](numberOfNewNodes);
            for (uint256 i = 0; i < numberOfNewNodes; ) {
                uint256 leftNode;

                // Assign the left node using the saved path or the position in the array.
                if ((i + nextLevelStartIndex) * 2 < currentLevelStartIndex) {
                    leftNode = self.sideNodes[level];
                } else {
                    leftNode = currentLevelNewNodes[(i + nextLevelStartIndex) * 2 - currentLevelStartIndex];
                }

                uint256 rightNode;

                // Assign the right node if the value exists.
                if ((i + nextLevelStartIndex) * 2 + 1 < currentLevelSize) {
                    rightNode = currentLevelNewNodes[(i + nextLevelStartIndex) * 2 + 1 - currentLevelStartIndex];
                }

                uint256 parentNode;

                // Assign the parent node.
                // If it has a right child the result will be the hash(leftNode, rightNode) if not,
                // it will be the leftNode.
                if (rightNode != 0) {
                    parentNode = PoseidonT3.hash([leftNode, rightNode]);
                } else {
                    parentNode = leftNode;
                }

                nextLevelNewNodes[i] = parentNode;

                unchecked {
                    ++i;
                }
            }

            // Update the `sideNodes` variable.
            // If `currentLevelSize` is odd, the saved value will be the last value of the array
            // if it is even and there are more than 1 element in `currentLevelNewNodes`, the saved value
            // will be the value before the last one.
            // If it is even and there is only one element, there is no need to save anything because
            // the correct value for this level was already saved before.
            if (currentLevelSize & 1 == 1) {
                self.sideNodes[level] = currentLevelNewNodes[currentLevelNewNodes.length - 1];
            } else if (currentLevelNewNodes.length > 1) {
                self.sideNodes[level] = currentLevelNewNodes[currentLevelNewNodes.length - 2];
            }

            currentLevelStartIndex = nextLevelStartIndex;

            // Calculate the next level startIndex value.
            // It is the position of the parent node which is pos/2.
            nextLevelStartIndex >>= 1;

            // Update the next array that will be used to calculate the next level.
            currentLevelNewNodes = nextLevelNewNodes;

            currentLevelSize = nextLevelSize;

            // Calculate the size of the next level.
            // The size of the next level is (currentLevelSize - 1) / 2 + 1.
            nextLevelSize = ((nextLevelSize - 1) >> 1) + 1;

            unchecked {
                ++level;
            }
        }

        // Update tree size
        self.size = treeSize + leaves.length;

        // Update tree root
        self.sideNodes[treeDepth] = currentLevelNewNodes[0];

        return currentLevelNewNodes[0];
    }

    /// @dev Updates the value of an existing leaf and recalculates hashes
    /// to maintain tree integrity.
    /// @param self: A storage reference to the 'LeanIMTData' struct.
    /// @param oldLeaf: The value of the leaf that is to be updated.
    /// @param newLeaf: The new value that will replace the oldLeaf in the tree.
    /// @param siblingNodes: An array of sibling nodes that are necessary to recalculate the path to the root.
    /// @return The new hash of the updated node after the leaf has been updated.
    function _update(
        LeanIMTData storage self,
        uint256 oldLeaf,
        uint256 newLeaf,
        uint256[] calldata siblingNodes
    ) internal returns (uint256) {
        if (newLeaf >= SNARK_SCALAR_FIELD) {
            revert LeafGreaterThanSnarkScalarField();
        } else if (!_has(self, oldLeaf)) {
            revert LeafDoesNotExist();
        } else if (_has(self, newLeaf)) {
            revert LeafAlreadyExists();
        }

        uint256 index = _indexOf(self, oldLeaf);
        uint256 node = newLeaf;
        uint256 oldRoot = oldLeaf;

        uint256 lastIndex = self.size - 1;
        uint256 i = 0;

        // Cache tree depth to optimize gas
        uint256 treeDepth = self.depth;

        for (uint256 level = 0; level < treeDepth; ) {
            if ((index >> level) & 1 == 1) {
                if (siblingNodes[i] >= SNARK_SCALAR_FIELD) {
                    revert LeafGreaterThanSnarkScalarField();
                }

                node = PoseidonT3.hash([siblingNodes[i], node]);
                oldRoot = PoseidonT3.hash([siblingNodes[i], oldRoot]);

                unchecked {
                    ++i;
                }
            } else {
                if (index >> level != lastIndex >> level) {
                    if (siblingNodes[i] >= SNARK_SCALAR_FIELD) {
                        revert LeafGreaterThanSnarkScalarField();
                    }

                    if (self.sideNodes[level] == oldRoot) {
                        self.sideNodes[level] = node;
                    }

                    node = PoseidonT3.hash([node, siblingNodes[i]]);
                    oldRoot = PoseidonT3.hash([oldRoot, siblingNodes[i]]);

                    unchecked {
                        ++i;
                    }
                } else {
                    self.sideNodes[level] = node;
                }
            }

            unchecked {
                ++level;
            }
        }

        if (oldRoot != _root(self)) {
            revert WrongSiblingNodes();
        }

        self.sideNodes[treeDepth] = node;

        if (newLeaf != 0) {
            self.leaves[newLeaf] = self.leaves[oldLeaf];
        }

        self.leaves[oldLeaf] = 0;

        return node;
    }

    /// @dev Removes a leaf from the tree by setting its value to zero.
    /// This function utilizes the update function to set the leaf's value
    /// to zero and update the tree's state accordingly.
    /// @param self: A storage reference to the 'LeanIMTData' struct.
    /// @param oldLeaf: The value of the leaf to be removed.
    /// @param siblingNodes: An array of sibling nodes required for updating the path to the root after removal.
    /// @return The new root hash of the tree after the leaf has been removed.
    function _remove(
        LeanIMTData storage self,
        uint256 oldLeaf,
        uint256[] calldata siblingNodes
    ) internal returns (uint256) {
        return _update(self, oldLeaf, 0, siblingNodes);
    }

    /// @dev Checks if a leaf exists in the tree.
    /// @param self: A storage reference to the 'LeanIMTData' struct.
    /// @param leaf: The value of the leaf to check for existence.
    /// @return A boolean value indicating whether the leaf exists in the tree.
    function _has(LeanIMTData storage self, uint256 leaf) internal view returns (bool) {
        return self.leaves[leaf] != 0;
    }

    /// @dev Retrieves the index of a given leaf in the tree.
    /// @param self: A storage reference to the 'LeanIMTData' struct.
    /// @param leaf: The value of the leaf whose index is to be found.
    /// @return The index of the specified leaf within the tree. If the leaf is not present, the function
    /// reverts with a custom error.
    function _indexOf(LeanIMTData storage self, uint256 leaf) internal view returns (uint256) {
        if (self.leaves[leaf] == 0) {
            revert LeafDoesNotExist();
        }

        return self.leaves[leaf] - 1;
    }

    /// @dev Retrieves the root of the tree from the 'sideNodes' mapping using the
    /// current tree depth.
    /// @param self: A storage reference to the 'LeanIMTData' struct.
    /// @return The root hash of the tree.
    function _root(LeanIMTData storage self) internal view returns (uint256) {
        return self.sideNodes[self.depth];
    }
}

File 4 of 24 : Constants.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;

uint256 constant SNARK_SCALAR_FIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617;

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

/// @title ICensusValidator
/// @notice Interface for validating census Merkle roots
/// @dev Implement this interface to enable external contracts to verify census roots
///      Useful for voting systems, governance contracts, and other on-chain mechanisms
///      that need to validate voting power at specific block numbers
interface ICensusValidator {
    /// @notice Validates a census root and returns the block number when it was set
    /// @dev Returns 0 if the root has never been set or has been evicted from history
    ///      The root history is maintained in a circular buffer (last 100 roots)
    /// @param root The census Merkle root to validate
    /// @return blockNumber The block number when this root was set (0 if invalid/evicted)
    function getRootBlockNumber(uint256 root) external view returns (uint256 blockNumber);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {IPoseidonT3} from "../interfaces/IPoseidonT3.sol";
import {IIdentityVerificationHubV2} from "../interfaces/IIdentityVerificationHubV2.sol";
import {ISelfVerificationRoot} from "../interfaces/ISelfVerificationRoot.sol";
import {CircuitConstantsV2} from "../constants/CircuitConstantsV2.sol";
import {AttestationId} from "../constants/AttestationId.sol";
import {SelfUtils} from "../libraries/SelfUtils.sol";
import {Formatter} from "../libraries/Formatter.sol";

/**
 * @title SelfVerificationRoot
 * @notice Abstract base contract to be integrated with self's verification infrastructure
 * @dev Provides base functionality for verifying and disclosing identity credentials
 * @author Self Team
 */
abstract contract SelfVerificationRoot is ISelfVerificationRoot {
    // ====================================================
    // Constants
    // ====================================================

    /// @notice Contract version identifier used in verification process
    /// @dev This version is included in the hub data for protocol compatibility
    uint8 constant CONTRACT_VERSION = 2;

    // ====================================================
    // Storage Variables
    // ====================================================

    /// @notice The scope value that proofs must match
    /// @dev Used to validate that submitted proofs match the expected scope
    uint256 internal _scope;

    /// @notice Reference to the identity verification hub V2 contract
    /// @dev Immutable reference used for bytes-based proof verification
    IIdentityVerificationHubV2 internal immutable _identityVerificationHubV2;

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

    /// @notice Error thrown when the data format is invalid
    /// @dev Triggered when the provided bytes data doesn't have the expected format
    error InvalidDataFormat();

    /// @notice Error thrown when onVerificationSuccess is called by an unauthorized address
    /// @dev Only the identity verification hub V2 contract can call onVerificationSuccess
    error UnauthorizedCaller();

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

    // ====================================================
    // Constructor
    // ====================================================

    /**
     * @notice Initializes the SelfVerificationRoot contract
     * @dev Sets up the immutable reference to the hub contract and generates scope automatically
     * @param identityVerificationHubV2Address The address of the Identity Verification Hub V2
     * @param scopeSeed The scope seed string to be hashed with contract address to generate the scope
     */
    constructor(address identityVerificationHubV2Address, string memory scopeSeed) {
        _identityVerificationHubV2 = IIdentityVerificationHubV2(identityVerificationHubV2Address);
        _scope = _calculateScope(address(this), scopeSeed, _getPoseidonAddress());
    }

    // ====================================================
    // Public Functions
    // ====================================================

    /**
     * @notice Returns the current scope value
     * @dev Public view function to access the current scope setting
     * @return The scope value that proofs must match
     */
    function scope() public view returns (uint256) {
        return _scope;
    }

    /**
     * @notice Verifies a self-proof using the bytes-based interface
     * @dev Parses relayer data format and validates against contract settings before calling hub V2
     * @param proofPayload Packed data from relayer in format: | 32 bytes attestationId | proof data |
     * @param userContextData User-defined data in format: | 32 bytes destChainId | 32 bytes userIdentifier | data |
     * @custom:data-format proofPayload = | 32 bytes attestationId | proofData |
     * @custom:data-format userContextData = | 32 bytes destChainId | 32 bytes userIdentifier | data |
     * @custom:data-format hubData = | 1 bytes contract version | 31 bytes buffer | 32 bytes scope | 32 bytes attestationId | proofData |
     */
    function verifySelfProof(bytes calldata proofPayload, bytes calldata userContextData) public {
        // Minimum expected length for proofData: 32 bytes attestationId + proof data
        if (proofPayload.length < 32) {
            revert InvalidDataFormat();
        }

        // Minimum userDefinedData length: 32 (destChainId) + 32 (userIdentifier) + 0 (userDefinedData) = 64 bytes
        if (userContextData.length < 64) {
            revert InvalidDataFormat();
        }

        bytes32 attestationId;
        assembly {
            // Load attestationId from the beginning of proofData (first 32 bytes)
            attestationId := calldataload(proofPayload.offset)
        }

        bytes32 destinationChainId = bytes32(userContextData[0:32]);
        bytes32 userIdentifier = bytes32(userContextData[32:64]);
        bytes memory userDefinedData = userContextData[64:];

        bytes32 configId = getConfigId(destinationChainId, userIdentifier, userDefinedData);

        // Hub data should be | 1 byte contractVersion | 31 bytes buffer | 32 bytes scope | 32 bytes attestationId | proof data
        bytes memory baseVerificationInput = abi.encodePacked(
            // 1 byte contractVersion
            CONTRACT_VERSION,
            // 31 bytes buffer (all zeros)
            bytes31(0),
            // 32 bytes scope
            _scope,
            proofPayload
        );

        // Call hub V2 verification
        _identityVerificationHubV2.verify(baseVerificationInput, bytes.concat(configId, userContextData));
    }

    /**
     * @notice Callback function called upon successful verification by the hub contract
     * @dev Only callable by the identity verification hub V2 contract for security
     * @param output The verification output data containing disclosed identity information
     * @param userData The user-defined data passed through the verification process
     * @custom:security Only the authorized hub contract can call this function
     * @custom:flow This function decodes the output and calls the customizable verification hook
     */
    function onVerificationSuccess(bytes memory output, bytes memory userData) public {
        // Only allow the identity verification hub V2 to call this function
        if (msg.sender != address(_identityVerificationHubV2)) {
            revert UnauthorizedCaller();
        }

        ISelfVerificationRoot.GenericDiscloseOutputV2 memory genericDiscloseOutput = abi.decode(
            output,
            (ISelfVerificationRoot.GenericDiscloseOutputV2)
        );

        // Call the customizable verification hook
        customVerificationHook(genericDiscloseOutput, userData);
    }

    /**
     * @notice Generates a configId for the user
     * @dev This function should be overridden by the implementing contract to provide custom configId logic
     * @param destinationChainId The destination chain ID
     * @param userIdentifier The user identifier
     * @param userDefinedData The user defined data
     * @return The configId
     */
    function getConfigId(
        bytes32 destinationChainId,
        bytes32 userIdentifier,
        bytes memory userDefinedData
    ) public view virtual returns (bytes32) {
        // Default implementation reverts; must be overridden in derived contract
        revert("SelfVerificationRoot: getConfigId must be overridden");
    }

    // ====================================================
    // Internal Functions
    // ====================================================

    /**
     * @notice Custom verification hook that can be overridden by implementing contracts
     * @dev This function is called after successful verification and hub address validation
     * @param output The verification output data from the hub containing disclosed identity information
     * @param userData The user-defined data passed through the verification process
     * @custom:override Override this function in derived contracts to add custom verification logic
     * @custom:security This function is only called after proper authentication by the hub contract
     */
    function customVerificationHook(
        ISelfVerificationRoot.GenericDiscloseOutputV2 memory output,
        bytes memory userData
    ) internal virtual {
        // Default implementation is empty - override in derived contracts to add custom logic
    }

    /**
     * @notice Gets the PoseidonT3 library address for the current chain
     * @dev Returns hardcoded addresses of pre-deployed PoseidonT3 library on current chain
     * @dev For local development networks, should create a setter function to set the scope manually
     * @return The address of the PoseidonT3 library on this chain
     */
    function _getPoseidonAddress() internal view returns (address) {
        uint256 chainId = block.chainid;

        // Celo Mainnet
        if (chainId == 42220) {
            return 0xF134707a4C4a3a76b8410fC0294d620A7c341581;
        }

        // Celo Sepolia
        if (chainId == 11142220) {
            return 0x0a782f7F9f8Aac6E0bacAF3cD4aA292C3275C6f2;
        }

        // For local/development networks or other chains, return zero address
        return address(0);
    }

    /**
     * @notice Calculates scope from contract address, scope seed, and PoseidonT3 address
     * @param contractAddress The contract address to hash
     * @param scopeSeed The scope seed string
     * @param poseidonT3Address The address of the PoseidonT3 library to use
     * @return The calculated scope value
     */
    function _calculateScope(
        address contractAddress,
        string memory scopeSeed,
        address poseidonT3Address
    ) internal view returns (uint256) {
        // Skip calculation if PoseidonT3 address is zero (local development)
        if (poseidonT3Address == address(0)) {
            return 0;
        }

        uint256 addressHash = _calculateAddressHashWithPoseidon(contractAddress, poseidonT3Address);
        uint256 scopeSeedAsUint = SelfUtils.stringToBigInt(scopeSeed);
        return IPoseidonT3(poseidonT3Address).hash([addressHash, scopeSeedAsUint]);
    }

    /**
     * @notice Calculates hash of contract address using frontend-compatible chunking with specific PoseidonT3
     * @dev Converts address to hex string, splits into 2 chunks (31+11), and hashes with provided PoseidonT3
     * @param addr The contract address to hash
     * @param poseidonT3Address The address of the PoseidonT3 library to use
     * @return The hash result equivalent to frontend's endpointHash for addresses
     */
    function _calculateAddressHashWithPoseidon(
        address addr,
        address poseidonT3Address
    ) internal view returns (uint256) {
        // Convert address to hex string (42 chars: "0x" + 40 hex digits)
        string memory addressString = SelfUtils.addressToHexString(addr);

        // Split into exactly 2 chunks: 31 + 11 characters
        // Chunk 1: characters 0-30 (31 chars)
        // Chunk 2: characters 31-41 (11 chars)
        uint256 chunk1BigInt = SelfUtils.stringToBigInt(Formatter.substring(addressString, 0, 31));
        uint256 chunk2BigInt = SelfUtils.stringToBigInt(Formatter.substring(addressString, 31, 42));

        return IPoseidonT3(poseidonT3Address).hash([chunk1BigInt, chunk2BigInt]);
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

/**
 * @title ISelfVerificationRoot
 * @notice Interface for self-verification infrastructure integration
 * @dev Provides base functionality for verifying and disclosing identity credentials
 */
interface ISelfVerificationRoot {
    /**
     * @notice Structure containing proof data for disclose circuits
     * @dev Contains the proof elements required for zero-knowledge verification
     * @param a First proof element
     * @param b Second proof element (2x2 matrix)
     * @param c Third proof element
     * @param pubSignals Array of 21 public signals for the circuit
     */
    struct DiscloseCircuitProof {
        uint256[2] a;
        uint256[2][2] b;
        uint256[2] c;
        uint256[21] pubSignals;
    }

    /**
     * @notice Structure containing verified identity disclosure output data
     * @dev Contains all disclosed identity information after successful verification
     * @param attestationId Unique identifier for the identity documents
     * @param userIdentifier Unique identifier for the user
     * @param nullifier Unique nullifier to prevent double-spending
     * @param forbiddenCountriesListPacked Packed representation of forbidden countries list
     * @param issuingState The state/country that issued the identity document
     * @param name Array of name components
     * @param idNumber The identity document number
     * @param nationality The nationality of the document holder
     * @param dateOfBirth Date of birth in string format
     * @param gender Gender of the document holder
     * @param expiryDate Expiry date of the identity document
     * @param olderThan Verified age threshold (e.g., 18 for adult verification)
     * @param ofac Array of OFAC (Office of Foreign Assets Control) compliance flags
     */
    struct GenericDiscloseOutputV2 {
        bytes32 attestationId;
        uint256 userIdentifier;
        uint256 nullifier;
        uint256[4] forbiddenCountriesListPacked;
        string issuingState;
        string[] name;
        string idNumber;
        string nationality;
        string dateOfBirth;
        string gender;
        string expiryDate;
        uint256 olderThan;
        bool[3] ofac;
    }

    /**
     * @notice Verifies a self-proof using the bytes-based interface
     * @dev Parses relayer data format and validates against contract settings before calling hub V2
     * @param proofPayload Packed data from relayer in format: | 32 bytes attestationId | proof data |
     * @param userContextData User-defined data in format: | 32 bytes configId | 32 bytes destChainId | 32 bytes userIdentifier | data |
     */
    function verifySelfProof(bytes calldata proofPayload, bytes calldata userContextData) external;

    /**
     * @notice Callback function called upon successful verification
     * @dev Only the identity verification hub V2 contract should call this function
     * @param output The verification output data containing disclosed identity information
     * @param userData The user-defined data passed through the verification process
     */
    function onVerificationSuccess(bytes memory output, bytes memory userData) external;
}

File 8 of 24 : SelfStructs.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

/**
 * @title SelfStructs
 * @dev Library containing data structures for Self protocol identity verification
 * @notice Defines structs for passport verification, EU ID verification, and generic disclosure outputs
 */
library SelfStructs {
    /**
     * @dev Header structure for Hub input containing contract version and scope information
     * @param contractVersion Version of the contract being used
     * @param scope Scope identifier for the verification request
     * @param attestationId Unique identifier for the attestation
     */
    struct HubInputHeader {
        uint8 contractVersion;
        uint256 scope;
        bytes32 attestationId;
    }

    /**
     * @dev Output structure for passport verification results
     * @param attestationId Unique identifier for the attestation
     * @param revealedDataPacked Packed binary data of revealed information
     * @param userIdentifier Unique identifier for the user
     * @param nullifier Cryptographic nullifier to prevent double-spending
     * @param forbiddenCountriesListPacked Packed list of forbidden countries (4 uint256 array)
     */
    struct PassportOutput {
        uint256 attestationId;
        bytes revealedDataPacked;
        uint256 userIdentifier;
        uint256 nullifier;
        uint256[4] forbiddenCountriesListPacked;
    }

    /**
     * @dev Output structure for EU ID verification results
     * @param attestationId Unique identifier for the attestation
     * @param revealedDataPacked Packed binary data of revealed information
     * @param userIdentifier Unique identifier for the user
     * @param nullifier Cryptographic nullifier to prevent double-spending
     * @param forbiddenCountriesListPacked Packed list of forbidden countries (4 uint256 array)
     */
    struct EuIdOutput {
        uint256 attestationId;
        bytes revealedDataPacked;
        uint256 userIdentifier;
        uint256 nullifier;
        uint256[4] forbiddenCountriesListPacked;
    }

    /**
     * @dev Output structure for Aadhaar verification results
     * @param attestationId Unique identifier for the attestation
     * @param revealedDataPacked Packed binary data of revealed information
     * @param userIdentifier Unique identifier for the user
     * @param nullifier Cryptographic nullifier to prevent double-spending
     */
    struct AadhaarOutput {
        uint256 attestationId;
        bytes revealedDataPacked;
        uint256 userIdentifier;
        uint256 nullifier;
        uint256[4] forbiddenCountriesListPacked;
    }

    /// @dev OFAC verification mode: Passport number only
    uint256 constant passportNoOfac = 0;
    /// @dev OFAC verification mode: Name and date of birth
    uint256 constant nameAndDobOfac = 1;
    /// @dev OFAC verification mode: Name and year of birth
    uint256 constant nameAndYobOfac = 2;

    /**
     * @dev Generic disclosure output structure (Version 2) with detailed personal information
     * @param attestationId Unique identifier for the attestation
     * @param userIdentifier Unique identifier for the user
     * @param nullifier Cryptographic nullifier to prevent double-spending
     * @param forbiddenCountriesListPacked Packed list of forbidden countries (4 uint256 array)
     * @param issuingState Country or state that issued the document
     * @param name Array of name components (first, middle, last names)
     * @param idNumber Government-issued identification number
     * @param nationality Nationality of the document holder
     * @param dateOfBirth Date of birth in string format
     * @param gender Gender of the document holder
     * @param expiryDate Document expiration date in string format
     * @param olderThan Minimum age verification result
     * @param ofac Array of OFAC (Office of Foreign Assets Control) verification results for different modes
     */
    struct GenericDiscloseOutputV2 {
        bytes32 attestationId;
        uint256 userIdentifier;
        uint256 nullifier;
        uint256[4] forbiddenCountriesListPacked;
        string issuingState;
        string[] name;
        string idNumber;
        string nationality;
        string dateOfBirth;
        string gender;
        string expiryDate;
        uint256 olderThan;
        bool[3] ofac;
    }

    /**
     * @dev Verification configuration structure (Version 1)
     * @param olderThanEnabled Whether minimum age verification is enabled
     * @param olderThan Minimum age requirement
     * @param forbiddenCountriesEnabled Whether forbidden countries check is enabled
     * @param forbiddenCountriesListPacked Packed list of forbidden countries (4 uint256 array)
     * @param ofacEnabled Array of boolean flags for different OFAC verification modes
     */
    struct VerificationConfigV1 {
        bool olderThanEnabled;
        uint256 olderThan;
        bool forbiddenCountriesEnabled;
        uint256[4] forbiddenCountriesListPacked;
        bool[3] ofacEnabled;
    }

    /**
     * @dev Verification configuration structure (Version 2)
     * @param olderThanEnabled Whether minimum age verification is enabled
     * @param olderThan Minimum age requirement
     * @param forbiddenCountriesEnabled Whether forbidden countries check is enabled
     * @param forbiddenCountriesListPacked Packed list of forbidden countries (4 uint256 array)
     * @param ofacEnabled Array of boolean flags for different OFAC verification modes
     */
    struct VerificationConfigV2 {
        bool olderThanEnabled;
        uint256 olderThan;
        bool forbiddenCountriesEnabled;
        uint256[4] forbiddenCountriesListPacked;
        bool[3] ofacEnabled;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {SelfStructs} from "./SelfStructs.sol";

library SelfUtils {
    struct UnformattedVerificationConfigV2 {
        uint256 olderThan;
        string[] forbiddenCountries;
        bool ofacEnabled;
    }

    /**
     * @dev Packs an array of forbidden countries into chunks suitable for circuit inputs
     * @param forbiddenCountries Array of 3-character country codes
     * @return output Array of 4 uint256 values containing packed country data
     */
    function packForbiddenCountriesList(
        string[] memory forbiddenCountries
    ) internal pure returns (uint256[4] memory output) {
        uint256 MAX_BYTES_IN_FIELD = 31;
        uint256 REQUIRED_CHUNKS = 4;

        // Convert country codes to bytes array
        bytes memory packedBytes;

        // Validate and pack country codes
        for (uint256 i = 0; i < forbiddenCountries.length; i++) {
            bytes memory countryBytes = bytes(forbiddenCountries[i]);

            // Validate country code length
            require(countryBytes.length == 3, "Invalid country code: must be exactly 3 characters long");

            // Append country code bytes
            packedBytes = abi.encodePacked(packedBytes, countryBytes);
        }

        uint256 maxBytes = packedBytes.length;
        uint256 packSize = MAX_BYTES_IN_FIELD;
        uint256 numChunks = (maxBytes + packSize - 1) / packSize; // Ceiling division

        // Pack bytes into chunks
        for (uint256 i = 0; i < numChunks && i < REQUIRED_CHUNKS; i++) {
            uint256 sum = 0;

            for (uint256 j = 0; j < packSize; j++) {
                uint256 idx = packSize * i + j;
                if (idx < maxBytes) {
                    uint256 value = uint256(uint8(packedBytes[idx]));
                    uint256 shift = 8 * j;
                    sum += value << shift;
                }
            }

            output[i] = sum;
        }

        // Remaining elements are already initialized to 0
        return output;
    }

    /**
     * @dev Formats an unstructured verification configuration into the standardized circuit-compatible format
     *
     * This function transforms a simplified input structure into the complete verification configuration
     * required by the verification config required by the hub.
     *
     * @notice Enabled Status Logic:
     * - `olderThanEnabled`: Automatically set to `true` when `olderThan > 0`
     * - `forbiddenCountriesEnabled`: Automatically set to `true` when `forbiddenCountries.length > 0`
     * - `ofacEnabled`: Uses the provided boolean value, replicated across all 3 OFAC check levels
     *
     *
     * @param unformattedVerificationConfigV2 The simplified input configuration containing:
     *        - `olderThan`: Minimum age threshold (0 = disabled, >0 = enabled)
     *        - `forbiddenCountries`: Array of 3-letter country codes (empty = disabled, non-empty = enabled)
     *        - `ofacEnabled`: Boolean flag for all OFAC verification levels
     *
     * @return verificationConfigV2 The formatted configuration ready for circuit consumption with:
     *         - Auto-computed enabled flags based on input values
     *         - Packed forbidden countries list for efficient circuit processing
     *         - Replicated OFAC settings across all verification levels
     */
    function formatVerificationConfigV2(
        UnformattedVerificationConfigV2 memory unformattedVerificationConfigV2
    ) internal pure returns (SelfStructs.VerificationConfigV2 memory verificationConfigV2) {
        bool[3] memory ofacArray;
        ofacArray[0] = unformattedVerificationConfigV2.ofacEnabled;
        ofacArray[1] = unformattedVerificationConfigV2.ofacEnabled;
        ofacArray[2] = unformattedVerificationConfigV2.ofacEnabled;

        verificationConfigV2 = SelfStructs.VerificationConfigV2({
            olderThanEnabled: unformattedVerificationConfigV2.olderThan > 0,
            olderThan: unformattedVerificationConfigV2.olderThan,
            forbiddenCountriesEnabled: unformattedVerificationConfigV2.forbiddenCountries.length > 0,
            forbiddenCountriesListPacked: packForbiddenCountriesList(
                unformattedVerificationConfigV2.forbiddenCountries
            ),
            ofacEnabled: ofacArray
        });
    }

    /**
     * @notice Convert string to BigInt using ASCII encoding
     * @dev Converts each character to its ASCII value and packs them into a uint256
     * @param str The input string (must be ASCII only, max 31 bytes)
     * @return The resulting BigInt value
     */
    function stringToBigInt(string memory str) internal pure returns (uint256) {
        bytes memory strBytes = bytes(str);
        require(strBytes.length <= 31, "String too long for BigInt conversion");

        uint256 result = 0;
        for (uint256 i = 0; i < strBytes.length; i++) {
            // Ensure ASCII only (0-127)
            require(uint8(strBytes[i]) <= 127, "Non-ASCII character detected");
            result = (result << 8) | uint256(uint8(strBytes[i]));
        }
        return result;
    }

    /**
     * @notice Converts an address to its lowercase hex string representation
     * @dev Produces a string like "0x1234567890abcdef..." (42 characters total)
     * @param addr The address to convert
     * @return The hex string representation of the address
     */
    function addressToHexString(address addr) internal pure returns (string memory) {
        bytes32 value = bytes32(uint256(uint160(addr)));
        bytes memory alphabet = "0123456789abcdef";
        bytes memory str = new bytes(42);

        str[0] = "0";
        str[1] = "x";
        for (uint256 i = 0; i < 20; i++) {
            str[2 + i * 2] = alphabet[uint8(value[i + 12] >> 4)];
            str[3 + i * 2] = alphabet[uint8(value[i + 12] & 0x0f)];
        }

        return string(str);
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {IRegisterCircuitVerifier} from "./IRegisterCircuitVerifier.sol";
import {IDscCircuitVerifier} from "./IDscCircuitVerifier.sol";
import {SelfStructs} from "../libraries/SelfStructs.sol";

/**
 * @title IIdentityVerificationHubV2
 * @notice Interface for the Identity Verification Hub V2 for verifying zero-knowledge proofs.
 * @dev Defines all external and public functions from IdentityVerificationHubImplV2.
 */
interface IIdentityVerificationHubV2 {
    // ====================================================
    // External Functions
    // ====================================================

    /**
     * @notice Registers a commitment using a register circuit proof.
     * @dev Verifies the register circuit proof and then calls the Identity Registry to register the commitment.
     * @param attestationId The attestation ID.
     * @param registerCircuitVerifierId The identifier for the register circuit verifier to use.
     * @param registerCircuitProof The register circuit proof data.
     */
    function registerCommitment(
        bytes32 attestationId,
        uint256 registerCircuitVerifierId,
        IRegisterCircuitVerifier.RegisterCircuitProof memory registerCircuitProof
    ) external;

    /**
     * @notice Registers a DSC key commitment using a DSC circuit proof.
     * @dev Verifies the DSC proof and then calls the Identity Registry to register the dsc key commitment.
     * @param attestationId The attestation ID.
     * @param dscCircuitVerifierId The identifier for the DSC circuit verifier to use.
     * @param dscCircuitProof The DSC circuit proof data.
     */
    function registerDscKeyCommitment(
        bytes32 attestationId,
        uint256 dscCircuitVerifierId,
        IDscCircuitVerifier.DscCircuitProof memory dscCircuitProof
    ) external;

    /**
     * @notice Sets verification config in V2 storage (owner only)
     * @dev The configId is automatically generated from the config content using sha256(abi.encode(config))
     * @param config The verification configuration
     * @return configId The generated config ID
     */
    function setVerificationConfigV2(
        SelfStructs.VerificationConfigV2 memory config
    ) external returns (bytes32 configId);

    /**
     * @notice Main verification function with new structured input format
     * @param baseVerificationInput The base verification input data
     * @param userContextData The user context data
     */
    function verify(bytes calldata baseVerificationInput, bytes calldata userContextData) external;

    /**
     * @notice Updates the registry address.
     * @param attestationId The attestation ID.
     * @param registryAddress The new registry address.
     */
    function updateRegistry(bytes32 attestationId, address registryAddress) external;

    /**
     * @notice Updates the VC and Disclose circuit verifier address.
     * @param attestationId The attestation ID.
     * @param vcAndDiscloseCircuitVerifierAddress The new VC and Disclose circuit verifier address.
     */
    function updateVcAndDiscloseCircuit(bytes32 attestationId, address vcAndDiscloseCircuitVerifierAddress) external;

    /**
     * @notice Updates the register circuit verifier for a specific signature type.
     * @param attestationId The attestation identifier.
     * @param typeId The signature type identifier.
     * @param verifierAddress The new register circuit verifier address.
     */
    function updateRegisterCircuitVerifier(bytes32 attestationId, uint256 typeId, address verifierAddress) external;

    /**
     * @notice Updates the DSC circuit verifier for a specific signature type.
     * @param attestationId The attestation identifier.
     * @param typeId The signature type identifier.
     * @param verifierAddress The new DSC circuit verifier address.
     */
    function updateDscVerifier(bytes32 attestationId, uint256 typeId, address verifierAddress) external;

    /**
     * @notice Batch updates register circuit verifiers.
     * @param attestationIds An array of attestation identifiers.
     * @param typeIds An array of signature type identifiers.
     * @param verifierAddresses An array of new register circuit verifier addresses.
     */
    function batchUpdateRegisterCircuitVerifiers(
        bytes32[] calldata attestationIds,
        uint256[] calldata typeIds,
        address[] calldata verifierAddresses
    ) external;

    /**
     * @notice Batch updates DSC circuit verifiers.
     * @param attestationIds An array of attestation identifiers.
     * @param typeIds An array of signature type identifiers.
     * @param verifierAddresses An array of new DSC circuit verifier addresses.
     */
    function batchUpdateDscCircuitVerifiers(
        bytes32[] calldata attestationIds,
        uint256[] calldata typeIds,
        address[] calldata verifierAddresses
    ) external;

    // ====================================================
    // External View Functions
    // ====================================================

    /**
     * @notice Returns the registry address for a given attestation ID.
     * @param attestationId The attestation ID to query.
     * @return The registry address associated with the attestation ID.
     */
    function registry(bytes32 attestationId) external view returns (address);

    /**
     * @notice Returns the disclose verifier address for a given attestation ID.
     * @param attestationId The attestation ID to query.
     * @return The disclose verifier address associated with the attestation ID.
     */
    function discloseVerifier(bytes32 attestationId) external view returns (address);

    /**
     * @notice Returns the register circuit verifier address for a given attestation ID and type ID.
     * @param attestationId The attestation ID to query.
     * @param typeId The type ID to query.
     * @return The register circuit verifier address associated with the attestation ID and type ID.
     */
    function registerCircuitVerifiers(bytes32 attestationId, uint256 typeId) external view returns (address);

    /**
     * @notice Returns the DSC circuit verifier address for a given attestation ID and type ID.
     * @param attestationId The attestation ID to query.
     * @param typeId The type ID to query.
     * @return The DSC circuit verifier address associated with the attestation ID and type ID.
     */
    function dscCircuitVerifiers(bytes32 attestationId, uint256 typeId) external view returns (address);

    /**
     * @notice Returns the merkle root timestamp for a given attestation ID and root.
     * @param attestationId The attestation ID to query.
     * @param root The merkle root to query.
     * @return The merkle root timestamp associated with the attestation ID and root.
     */
    function rootTimestamp(bytes32 attestationId, uint256 root) external view returns (uint256);

    /**
     * @notice Returns the identity commitment merkle root for a given attestation ID.
     * @param attestationId The attestation ID to query.
     * @return The identity commitment merkle root associated with the attestation ID.
     */
    function getIdentityCommitmentMerkleRoot(bytes32 attestationId) external view returns (uint256);

    /**
     * @notice Checks if a verification config exists
     * @param configId The configuration identifier
     * @return exists Whether the config exists
     */
    function verificationConfigV2Exists(bytes32 configId) external view returns (bool exists);

    // ====================================================
    // Public Functions
    // ====================================================

    /**
     * @notice Generates a config ID from a verification config
     * @param config The verification configuration
     * @return The generated config ID (sha256 hash of encoded config)
     */
    function generateConfigId(SelfStructs.VerificationConfigV2 memory config) external pure returns (bytes32);
}

File 11 of 24 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

import {Panic} from "../Panic.sol";
import {SafeCast} from "./SafeCast.sol";

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Return the 512-bit addition of two uint256.
     *
     * The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.
     */
    function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
        assembly ("memory-safe") {
            low := add(a, b)
            high := lt(low, a)
        }
    }

    /**
     * @dev Return the 512-bit multiplication of two uint256.
     *
     * The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.
     */
    function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
        // 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
        // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
        // variables such that product = high * 2²⁵⁶ + low.
        assembly ("memory-safe") {
            let mm := mulmod(a, b, not(0))
            low := mul(a, b)
            high := sub(sub(mm, low), lt(mm, low))
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, with a success flag (no overflow).
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            uint256 c = a + b;
            success = c >= a;
            result = c * SafeCast.toUint(success);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            uint256 c = a - b;
            success = c <= a;
            result = c * SafeCast.toUint(success);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            uint256 c = a * b;
            assembly ("memory-safe") {
                // Only true when the multiplication doesn't overflow
                // (c / a == b) || (a == 0)
                success := or(eq(div(c, a), b), iszero(a))
            }
            // equivalent to: success ? c : 0
            result = c * SafeCast.toUint(success);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            success = b > 0;
            assembly ("memory-safe") {
                // The `DIV` opcode returns zero when the denominator is 0.
                result := div(a, b)
            }
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            success = b > 0;
            assembly ("memory-safe") {
                // The `MOD` opcode returns zero when the denominator is 0.
                result := mod(a, b)
            }
        }
    }

    /**
     * @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.
     */
    function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {
        (bool success, uint256 result) = tryAdd(a, b);
        return ternary(success, result, type(uint256).max);
    }

    /**
     * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.
     */
    function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {
        (, uint256 result) = trySub(a, b);
        return result;
    }

    /**
     * @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.
     */
    function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {
        (bool success, uint256 result) = tryMul(a, b);
        return ternary(success, result, type(uint256).max);
    }

    /**
     * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
     *
     * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
     * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
     * one branch when needed, making this function more expensive.
     */
    function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
        unchecked {
            // branchless ternary works because:
            // b ^ (a ^ b) == a
            // b ^ 0 == b
            return b ^ ((a ^ b) * SafeCast.toUint(condition));
        }
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return ternary(a > b, a, b);
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return ternary(a < b, a, b);
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }

        // The following calculation ensures accurate ceiling division without overflow.
        // Since a is non-zero, (a - 1) / b will not overflow.
        // The largest possible result occurs when (a - 1) / b is type(uint256).max,
        // but the largest value we can obtain is type(uint256).max - 1, which happens
        // when a = type(uint256).max and b = 1.
        unchecked {
            return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
        }
    }

    /**
     * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     *
     * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            (uint256 high, uint256 low) = mul512(x, y);

            // Handle non-overflow cases, 256 by 256 division.
            if (high == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return low / denominator;
            }

            // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
            if (denominator <= high) {
                Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [high low].
            uint256 remainder;
            assembly ("memory-safe") {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                high := sub(high, gt(remainder, low))
                low := sub(low, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly ("memory-safe") {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [high low] by twos.
                low := div(low, twos)

                // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from high into low.
            low |= high * twos;

            // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
            // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv ≡ 1 mod 2⁴.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2⁸
            inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
            inverse *= 2 - denominator * inverse; // inverse mod 2³²
            inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
            inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
            inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is
            // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high
            // is no longer required.
            result = low * inverse;
            return result;
        }
    }

    /**
     * @dev Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
    }

    /**
     * @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.
     */
    function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {
        unchecked {
            (uint256 high, uint256 low) = mul512(x, y);
            if (high >= 1 << n) {
                Panic.panic(Panic.UNDER_OVERFLOW);
            }
            return (high << (256 - n)) | (low >> n);
        }
    }

    /**
     * @dev Calculates x * y >> n with full precision, following the selected rounding direction.
     */
    function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {
        return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);
    }

    /**
     * @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
     *
     * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.
     * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
     *
     * If the input value is not inversible, 0 is returned.
     *
     * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the
     * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
     */
    function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
        unchecked {
            if (n == 0) return 0;

            // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
            // Used to compute integers x and y such that: ax + ny = gcd(a, n).
            // When the gcd is 1, then the inverse of a modulo n exists and it's x.
            // ax + ny = 1
            // ax = 1 + (-y)n
            // ax ≡ 1 (mod n) # x is the inverse of a modulo n

            // If the remainder is 0 the gcd is n right away.
            uint256 remainder = a % n;
            uint256 gcd = n;

            // Therefore the initial coefficients are:
            // ax + ny = gcd(a, n) = n
            // 0a + 1n = n
            int256 x = 0;
            int256 y = 1;

            while (remainder != 0) {
                uint256 quotient = gcd / remainder;

                (gcd, remainder) = (
                    // The old remainder is the next gcd to try.
                    remainder,
                    // Compute the next remainder.
                    // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
                    // where gcd is at most n (capped to type(uint256).max)
                    gcd - remainder * quotient
                );

                (x, y) = (
                    // Increment the coefficient of a.
                    y,
                    // Decrement the coefficient of n.
                    // Can overflow, but the result is casted to uint256 so that the
                    // next value of y is "wrapped around" to a value between 0 and n - 1.
                    x - y * int256(quotient)
                );
            }

            if (gcd != 1) return 0; // No inverse exists.
            return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
        }
    }

    /**
     * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
     *
     * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
     * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
     * `a**(p-2)` is the modular multiplicative inverse of a in Fp.
     *
     * NOTE: this function does NOT check that `p` is a prime greater than `2`.
     */
    function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
        unchecked {
            return Math.modExp(a, p - 2, p);
        }
    }

    /**
     * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
     *
     * Requirements:
     * - modulus can't be zero
     * - underlying staticcall to precompile must succeed
     *
     * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
     * sure the chain you're using it on supports the precompiled contract for modular exponentiation
     * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
     * the underlying function will succeed given the lack of a revert, but the result may be incorrectly
     * interpreted as 0.
     */
    function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
        (bool success, uint256 result) = tryModExp(b, e, m);
        if (!success) {
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }
        return result;
    }

    /**
     * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
     * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying
     * to operate modulo 0 or if the underlying precompile reverted.
     *
     * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
     * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
     * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
     * of a revert, but the result may be incorrectly interpreted as 0.
     */
    function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
        if (m == 0) return (false, 0);
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            // | Offset    | Content    | Content (Hex)                                                      |
            // |-----------|------------|--------------------------------------------------------------------|
            // | 0x00:0x1f | size of b  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
            // | 0x20:0x3f | size of e  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
            // | 0x40:0x5f | size of m  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
            // | 0x60:0x7f | value of b | 0x<.............................................................b> |
            // | 0x80:0x9f | value of e | 0x<.............................................................e> |
            // | 0xa0:0xbf | value of m | 0x<.............................................................m> |
            mstore(ptr, 0x20)
            mstore(add(ptr, 0x20), 0x20)
            mstore(add(ptr, 0x40), 0x20)
            mstore(add(ptr, 0x60), b)
            mstore(add(ptr, 0x80), e)
            mstore(add(ptr, 0xa0), m)

            // Given the result < m, it's guaranteed to fit in 32 bytes,
            // so we can use the memory scratch space located at offset 0.
            success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)
            result := mload(0x00)
        }
    }

    /**
     * @dev Variant of {modExp} that supports inputs of arbitrary length.
     */
    function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {
        (bool success, bytes memory result) = tryModExp(b, e, m);
        if (!success) {
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }
        return result;
    }

    /**
     * @dev Variant of {tryModExp} that supports inputs of arbitrary length.
     */
    function tryModExp(
        bytes memory b,
        bytes memory e,
        bytes memory m
    ) internal view returns (bool success, bytes memory result) {
        if (_zeroBytes(m)) return (false, new bytes(0));

        uint256 mLen = m.length;

        // Encode call args in result and move the free memory pointer
        result = abi.encodePacked(b.length, e.length, mLen, b, e, m);

        assembly ("memory-safe") {
            let dataPtr := add(result, 0x20)
            // Write result on top of args to avoid allocating extra memory.
            success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)
            // Overwrite the length.
            // result.length > returndatasize() is guaranteed because returndatasize() == m.length
            mstore(result, mLen)
            // Set the memory pointer after the returned data.
            mstore(0x40, add(dataPtr, mLen))
        }
    }

    /**
     * @dev Returns whether the provided byte array is zero.
     */
    function _zeroBytes(bytes memory byteArray) private pure returns (bool) {
        for (uint256 i = 0; i < byteArray.length; ++i) {
            if (byteArray[i] != 0) {
                return false;
            }
        }
        return true;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * This method is based on Newton's method for computing square roots; the algorithm is restricted to only
     * using integer operations.
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        unchecked {
            // Take care of easy edge cases when a == 0 or a == 1
            if (a <= 1) {
                return a;
            }

            // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a
            // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between
            // the current value as `ε_n = | x_n - sqrt(a) |`.
            //
            // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root
            // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is
            // bigger than any uint256.
            //
            // By noticing that
            // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`
            // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar
            // to the msb function.
            uint256 aa = a;
            uint256 xn = 1;

            if (aa >= (1 << 128)) {
                aa >>= 128;
                xn <<= 64;
            }
            if (aa >= (1 << 64)) {
                aa >>= 64;
                xn <<= 32;
            }
            if (aa >= (1 << 32)) {
                aa >>= 32;
                xn <<= 16;
            }
            if (aa >= (1 << 16)) {
                aa >>= 16;
                xn <<= 8;
            }
            if (aa >= (1 << 8)) {
                aa >>= 8;
                xn <<= 4;
            }
            if (aa >= (1 << 4)) {
                aa >>= 4;
                xn <<= 2;
            }
            if (aa >= (1 << 2)) {
                xn <<= 1;
            }

            // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).
            //
            // We can refine our estimation by noticing that the middle of that interval minimizes the error.
            // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).
            // This is going to be our x_0 (and ε_0)
            xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)

            // From here, Newton's method give us:
            // x_{n+1} = (x_n + a / x_n) / 2
            //
            // One should note that:
            // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a
            //              = ((x_n² + a) / (2 * x_n))² - a
            //              = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a
            //              = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)
            //              = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)
            //              = (x_n² - a)² / (2 * x_n)²
            //              = ((x_n² - a) / (2 * x_n))²
            //              ≥ 0
            // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n
            //
            // This gives us the proof of quadratic convergence of the sequence:
            // ε_{n+1} = | x_{n+1} - sqrt(a) |
            //         = | (x_n + a / x_n) / 2 - sqrt(a) |
            //         = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |
            //         = | (x_n - sqrt(a))² / (2 * x_n) |
            //         = | ε_n² / (2 * x_n) |
            //         = ε_n² / | (2 * x_n) |
            //
            // For the first iteration, we have a special case where x_0 is known:
            // ε_1 = ε_0² / | (2 * x_0) |
            //     ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))
            //     ≤ 2**(2*e-4) / (3 * 2**(e-1))
            //     ≤ 2**(e-3) / 3
            //     ≤ 2**(e-3-log2(3))
            //     ≤ 2**(e-4.5)
            //
            // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:
            // ε_{n+1} = ε_n² / | (2 * x_n) |
            //         ≤ (2**(e-k))² / (2 * 2**(e-1))
            //         ≤ 2**(2*e-2*k) / 2**e
            //         ≤ 2**(e-2*k)
            xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5)  -- special case, see above
            xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9)    -- general case with k = 4.5
            xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18)   -- general case with k = 9
            xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36)   -- general case with k = 18
            xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72)   -- general case with k = 36
            xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144)  -- general case with k = 72

            // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision
            // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either
            // sqrt(a) or sqrt(a) + 1.
            return xn - SafeCast.toUint(xn > a / xn);
        }
    }

    /**
     * @dev Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 x) internal pure returns (uint256 r) {
        // If value has upper 128 bits set, log2 result is at least 128
        r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
        // If upper 64 bits of 128-bit half set, add 64 to result
        r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
        // If upper 32 bits of 64-bit half set, add 32 to result
        r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
        // If upper 16 bits of 32-bit half set, add 16 to result
        r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
        // If upper 8 bits of 16-bit half set, add 8 to result
        r |= SafeCast.toUint((x >> r) > 0xff) << 3;
        // If upper 4 bits of 8-bit half set, add 4 to result
        r |= SafeCast.toUint((x >> r) > 0xf) << 2;

        // Shifts value right by the current result and use it as an index into this lookup table:
        //
        // | x (4 bits) |  index  | table[index] = MSB position |
        // |------------|---------|-----------------------------|
        // |    0000    |    0    |        table[0] = 0         |
        // |    0001    |    1    |        table[1] = 0         |
        // |    0010    |    2    |        table[2] = 1         |
        // |    0011    |    3    |        table[3] = 1         |
        // |    0100    |    4    |        table[4] = 2         |
        // |    0101    |    5    |        table[5] = 2         |
        // |    0110    |    6    |        table[6] = 2         |
        // |    0111    |    7    |        table[7] = 2         |
        // |    1000    |    8    |        table[8] = 3         |
        // |    1001    |    9    |        table[9] = 3         |
        // |    1010    |   10    |        table[10] = 3        |
        // |    1011    |   11    |        table[11] = 3        |
        // |    1100    |   12    |        table[12] = 3        |
        // |    1101    |   13    |        table[13] = 3        |
        // |    1110    |   14    |        table[14] = 3        |
        // |    1111    |   15    |        table[15] = 3        |
        //
        // The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.
        assembly ("memory-safe") {
            r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))
        }
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 x) internal pure returns (uint256 r) {
        // If value has upper 128 bits set, log2 result is at least 128
        r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
        // If upper 64 bits of 128-bit half set, add 64 to result
        r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
        // If upper 32 bits of 64-bit half set, add 32 to result
        r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
        // If upper 16 bits of 32-bit half set, add 16 to result
        r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
        // Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8
        return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

File 12 of 24 : Arrays.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/Arrays.sol)
// This file was procedurally generated from scripts/generate/templates/Arrays.js.

pragma solidity ^0.8.20;

import {Comparators} from "./Comparators.sol";
import {SlotDerivation} from "./SlotDerivation.sol";
import {StorageSlot} from "./StorageSlot.sol";
import {Math} from "./math/Math.sol";

/**
 * @dev Collection of functions related to array types.
 */
library Arrays {
    using SlotDerivation for bytes32;
    using StorageSlot for bytes32;

    /**
     * @dev Sort an array of uint256 (in memory) following the provided comparator function.
     *
     * This function does the sorting "in place", meaning that it overrides the input. The object is returned for
     * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
     *
     * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the
     * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
     * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
     * consume more gas than is available in a block, leading to potential DoS.
     *
     * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
     */
    function sort(
        uint256[] memory array,
        function(uint256, uint256) pure returns (bool) comp
    ) internal pure returns (uint256[] memory) {
        _quickSort(_begin(array), _end(array), comp);
        return array;
    }

    /**
     * @dev Variant of {sort} that sorts an array of uint256 in increasing order.
     */
    function sort(uint256[] memory array) internal pure returns (uint256[] memory) {
        sort(array, Comparators.lt);
        return array;
    }

    /**
     * @dev Sort an array of address (in memory) following the provided comparator function.
     *
     * This function does the sorting "in place", meaning that it overrides the input. The object is returned for
     * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
     *
     * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the
     * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
     * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
     * consume more gas than is available in a block, leading to potential DoS.
     *
     * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
     */
    function sort(
        address[] memory array,
        function(address, address) pure returns (bool) comp
    ) internal pure returns (address[] memory) {
        sort(_castToUint256Array(array), _castToUint256Comp(comp));
        return array;
    }

    /**
     * @dev Variant of {sort} that sorts an array of address in increasing order.
     */
    function sort(address[] memory array) internal pure returns (address[] memory) {
        sort(_castToUint256Array(array), Comparators.lt);
        return array;
    }

    /**
     * @dev Sort an array of bytes32 (in memory) following the provided comparator function.
     *
     * This function does the sorting "in place", meaning that it overrides the input. The object is returned for
     * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
     *
     * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the
     * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
     * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
     * consume more gas than is available in a block, leading to potential DoS.
     *
     * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
     */
    function sort(
        bytes32[] memory array,
        function(bytes32, bytes32) pure returns (bool) comp
    ) internal pure returns (bytes32[] memory) {
        sort(_castToUint256Array(array), _castToUint256Comp(comp));
        return array;
    }

    /**
     * @dev Variant of {sort} that sorts an array of bytes32 in increasing order.
     */
    function sort(bytes32[] memory array) internal pure returns (bytes32[] memory) {
        sort(_castToUint256Array(array), Comparators.lt);
        return array;
    }

    /**
     * @dev Performs a quick sort of a segment of memory. The segment sorted starts at `begin` (inclusive), and stops
     * at end (exclusive). Sorting follows the `comp` comparator.
     *
     * Invariant: `begin <= end`. This is the case when initially called by {sort} and is preserved in subcalls.
     *
     * IMPORTANT: Memory locations between `begin` and `end` are not validated/zeroed. This function should
     * be used only if the limits are within a memory array.
     */
    function _quickSort(uint256 begin, uint256 end, function(uint256, uint256) pure returns (bool) comp) private pure {
        unchecked {
            if (end - begin < 0x40) return;

            // Use first element as pivot
            uint256 pivot = _mload(begin);
            // Position where the pivot should be at the end of the loop
            uint256 pos = begin;

            for (uint256 it = begin + 0x20; it < end; it += 0x20) {
                if (comp(_mload(it), pivot)) {
                    // If the value stored at the iterator's position comes before the pivot, we increment the
                    // position of the pivot and move the value there.
                    pos += 0x20;
                    _swap(pos, it);
                }
            }

            _swap(begin, pos); // Swap pivot into place
            _quickSort(begin, pos, comp); // Sort the left side of the pivot
            _quickSort(pos + 0x20, end, comp); // Sort the right side of the pivot
        }
    }

    /**
     * @dev Pointer to the memory location of the first element of `array`.
     */
    function _begin(uint256[] memory array) private pure returns (uint256 ptr) {
        assembly ("memory-safe") {
            ptr := add(array, 0x20)
        }
    }

    /**
     * @dev Pointer to the memory location of the first memory word (32bytes) after `array`. This is the memory word
     * that comes just after the last element of the array.
     */
    function _end(uint256[] memory array) private pure returns (uint256 ptr) {
        unchecked {
            return _begin(array) + array.length * 0x20;
        }
    }

    /**
     * @dev Load memory word (as a uint256) at location `ptr`.
     */
    function _mload(uint256 ptr) private pure returns (uint256 value) {
        assembly {
            value := mload(ptr)
        }
    }

    /**
     * @dev Swaps the elements memory location `ptr1` and `ptr2`.
     */
    function _swap(uint256 ptr1, uint256 ptr2) private pure {
        assembly {
            let value1 := mload(ptr1)
            let value2 := mload(ptr2)
            mstore(ptr1, value2)
            mstore(ptr2, value1)
        }
    }

    /// @dev Helper: low level cast address memory array to uint256 memory array
    function _castToUint256Array(address[] memory input) private pure returns (uint256[] memory output) {
        assembly {
            output := input
        }
    }

    /// @dev Helper: low level cast bytes32 memory array to uint256 memory array
    function _castToUint256Array(bytes32[] memory input) private pure returns (uint256[] memory output) {
        assembly {
            output := input
        }
    }

    /// @dev Helper: low level cast address comp function to uint256 comp function
    function _castToUint256Comp(
        function(address, address) pure returns (bool) input
    ) private pure returns (function(uint256, uint256) pure returns (bool) output) {
        assembly {
            output := input
        }
    }

    /// @dev Helper: low level cast bytes32 comp function to uint256 comp function
    function _castToUint256Comp(
        function(bytes32, bytes32) pure returns (bool) input
    ) private pure returns (function(uint256, uint256) pure returns (bool) output) {
        assembly {
            output := input
        }
    }

    /**
     * @dev Searches a sorted `array` and returns the first index that contains
     * a value greater or equal to `element`. If no such index exists (i.e. all
     * values in the array are strictly less than `element`), the array length is
     * returned. Time complexity O(log n).
     *
     * NOTE: The `array` is expected to be sorted in ascending order, and to
     * contain no repeated elements.
     *
     * IMPORTANT: Deprecated. This implementation behaves as {lowerBound} but lacks
     * support for repeated elements in the array. The {lowerBound} function should
     * be used instead.
     */
    function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
        uint256 low = 0;
        uint256 high = array.length;

        if (high == 0) {
            return 0;
        }

        while (low < high) {
            uint256 mid = Math.average(low, high);

            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)
            // because Math.average rounds towards zero (it does integer division with truncation).
            if (unsafeAccess(array, mid).value > element) {
                high = mid;
            } else {
                low = mid + 1;
            }
        }

        // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
        if (low > 0 && unsafeAccess(array, low - 1).value == element) {
            return low - 1;
        } else {
            return low;
        }
    }

    /**
     * @dev Searches an `array` sorted in ascending order and returns the first
     * index that contains a value greater or equal than `element`. If no such index
     * exists (i.e. all values in the array are strictly less than `element`), the array
     * length is returned. Time complexity O(log n).
     *
     * See C++'s https://en.cppreference.com/w/cpp/algorithm/lower_bound[lower_bound].
     */
    function lowerBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
        uint256 low = 0;
        uint256 high = array.length;

        if (high == 0) {
            return 0;
        }

        while (low < high) {
            uint256 mid = Math.average(low, high);

            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)
            // because Math.average rounds towards zero (it does integer division with truncation).
            if (unsafeAccess(array, mid).value < element) {
                // this cannot overflow because mid < high
                unchecked {
                    low = mid + 1;
                }
            } else {
                high = mid;
            }
        }

        return low;
    }

    /**
     * @dev Searches an `array` sorted in ascending order and returns the first
     * index that contains a value strictly greater than `element`. If no such index
     * exists (i.e. all values in the array are strictly less than `element`), the array
     * length is returned. Time complexity O(log n).
     *
     * See C++'s https://en.cppreference.com/w/cpp/algorithm/upper_bound[upper_bound].
     */
    function upperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
        uint256 low = 0;
        uint256 high = array.length;

        if (high == 0) {
            return 0;
        }

        while (low < high) {
            uint256 mid = Math.average(low, high);

            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)
            // because Math.average rounds towards zero (it does integer division with truncation).
            if (unsafeAccess(array, mid).value > element) {
                high = mid;
            } else {
                // this cannot overflow because mid < high
                unchecked {
                    low = mid + 1;
                }
            }
        }

        return low;
    }

    /**
     * @dev Same as {lowerBound}, but with an array in memory.
     */
    function lowerBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {
        uint256 low = 0;
        uint256 high = array.length;

        if (high == 0) {
            return 0;
        }

        while (low < high) {
            uint256 mid = Math.average(low, high);

            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)
            // because Math.average rounds towards zero (it does integer division with truncation).
            if (unsafeMemoryAccess(array, mid) < element) {
                // this cannot overflow because mid < high
                unchecked {
                    low = mid + 1;
                }
            } else {
                high = mid;
            }
        }

        return low;
    }

    /**
     * @dev Same as {upperBound}, but with an array in memory.
     */
    function upperBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {
        uint256 low = 0;
        uint256 high = array.length;

        if (high == 0) {
            return 0;
        }

        while (low < high) {
            uint256 mid = Math.average(low, high);

            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)
            // because Math.average rounds towards zero (it does integer division with truncation).
            if (unsafeMemoryAccess(array, mid) > element) {
                high = mid;
            } else {
                // this cannot overflow because mid < high
                unchecked {
                    low = mid + 1;
                }
            }
        }

        return low;
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {
        bytes32 slot;
        assembly ("memory-safe") {
            slot := arr.slot
        }
        return slot.deriveArray().offset(pos).getAddressSlot();
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {
        bytes32 slot;
        assembly ("memory-safe") {
            slot := arr.slot
        }
        return slot.deriveArray().offset(pos).getBytes32Slot();
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {
        bytes32 slot;
        assembly ("memory-safe") {
            slot := arr.slot
        }
        return slot.deriveArray().offset(pos).getUint256Slot();
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeAccess(bytes[] storage arr, uint256 pos) internal pure returns (StorageSlot.BytesSlot storage) {
        bytes32 slot;
        assembly ("memory-safe") {
            slot := arr.slot
        }
        return slot.deriveArray().offset(pos).getBytesSlot();
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeAccess(string[] storage arr, uint256 pos) internal pure returns (StorageSlot.StringSlot storage) {
        bytes32 slot;
        assembly ("memory-safe") {
            slot := arr.slot
        }
        return slot.deriveArray().offset(pos).getStringSlot();
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {
        assembly {
            res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
        }
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeMemoryAccess(bytes32[] memory arr, uint256 pos) internal pure returns (bytes32 res) {
        assembly {
            res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
        }
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {
        assembly {
            res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
        }
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeMemoryAccess(bytes[] memory arr, uint256 pos) internal pure returns (bytes memory res) {
        assembly {
            res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
        }
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeMemoryAccess(string[] memory arr, uint256 pos) internal pure returns (string memory res) {
        assembly {
            res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
        }
    }

    /**
     * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
     *
     * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
     */
    function unsafeSetLength(address[] storage array, uint256 len) internal {
        assembly ("memory-safe") {
            sstore(array.slot, len)
        }
    }

    /**
     * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
     *
     * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
     */
    function unsafeSetLength(bytes32[] storage array, uint256 len) internal {
        assembly ("memory-safe") {
            sstore(array.slot, len)
        }
    }

    /**
     * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
     *
     * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
     */
    function unsafeSetLength(uint256[] storage array, uint256 len) internal {
        assembly ("memory-safe") {
            sstore(array.slot, len)
        }
    }

    /**
     * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
     *
     * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
     */
    function unsafeSetLength(bytes[] storage array, uint256 len) internal {
        assembly ("memory-safe") {
            sstore(array.slot, len)
        }
    }

    /**
     * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
     *
     * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
     */
    function unsafeSetLength(string[] storage array, uint256 len) internal {
        assembly ("memory-safe") {
            sstore(array.slot, len)
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)

pragma solidity ^0.8.20;

/**
 * @dev Helper library for emitting standardized panic codes.
 *
 * ```solidity
 * contract Example {
 *      using Panic for uint256;
 *
 *      // Use any of the declared internal constants
 *      function foo() { Panic.GENERIC.panic(); }
 *
 *      // Alternatively
 *      function foo() { Panic.panic(Panic.GENERIC); }
 * }
 * ```
 *
 * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
 *
 * _Available since v5.1._
 */
// slither-disable-next-line unused-state
library Panic {
    /// @dev generic / unspecified error
    uint256 internal constant GENERIC = 0x00;
    /// @dev used by the assert() builtin
    uint256 internal constant ASSERT = 0x01;
    /// @dev arithmetic underflow or overflow
    uint256 internal constant UNDER_OVERFLOW = 0x11;
    /// @dev division or modulo by zero
    uint256 internal constant DIVISION_BY_ZERO = 0x12;
    /// @dev enum conversion error
    uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;
    /// @dev invalid encoding in storage
    uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;
    /// @dev empty array pop
    uint256 internal constant EMPTY_ARRAY_POP = 0x31;
    /// @dev array out of bounds access
    uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
    /// @dev resource error (too large allocation or too large array)
    uint256 internal constant RESOURCE_ERROR = 0x41;
    /// @dev calling invalid internal function
    uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;

    /// @dev Reverts with a panic code. Recommended to use with
    /// the internal constants with predefined codes.
    function panic(uint256 code) internal pure {
        assembly ("memory-safe") {
            mstore(0x00, 0x4e487b71)
            mstore(0x20, code)
            revert(0x1c, 0x24)
        }
    }
}

/// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0;

library PoseidonT3 {
  uint constant M00 = 0x109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b;
  uint constant M01 = 0x2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771;
  uint constant M02 = 0x143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7;
  uint constant M10 = 0x16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e0;
  uint constant M11 = 0x2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe23;
  uint constant M12 = 0x176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee2911;

  // See here for a simplified implementation: https://github.com/vimwitch/poseidon-solidity/blob/e57becdabb65d99fdc586fe1e1e09e7108202d53/contracts/Poseidon.sol#L40
  // Inspired by: https://github.com/iden3/circomlibjs/blob/v0.0.8/src/poseidon_slow.js
  function hash(uint[2] memory) public pure returns (uint) {
    assembly {
      let F := 21888242871839275222246405745257275088548364400416034343698204186575808495617
      let M20 := 0x2b90bba00fca0589f617e7dcbfe82e0df706ab640ceb247b791a93b74e36736d
      let M21 := 0x101071f0032379b697315876690f053d148d4e109f5fb065c8aacc55a0f89bfa
      let M22 := 0x19a3fc0a56702bf417ba7fee3802593fa644470307043f7773279cd71d25d5e0

      // load the inputs from memory
      let state1 := add(mod(mload(0x80), F), 0x00f1445235f2148c5986587169fc1bcd887b08d4d00868df5696fff40956e864)
      let state2 := add(mod(mload(0xa0), F), 0x08dff3487e8ac99e1f29a058d0fa80b930c728730b7ab36ce879f3890ecf73f5)
      let scratch0 := mulmod(state1, state1, F)
      state1 := mulmod(mulmod(scratch0, scratch0, F), state1, F)
      scratch0 := mulmod(state2, state2, F)
      state2 := mulmod(mulmod(scratch0, scratch0, F), state2, F)
      scratch0 := add(
        0x2f27be690fdaee46c3ce28f7532b13c856c35342c84bda6e20966310fadc01d0,
        add(add(15452833169820924772166449970675545095234312153403844297388521437673434406763, mulmod(state1, M10, F)), mulmod(state2, M20, F))
      )
      let scratch1 := add(
        0x2b2ae1acf68b7b8d2416bebf3d4f6234b763fe04b8043ee48b8327bebca16cf2,
        add(add(18674271267752038776579386132900109523609358935013267566297499497165104279117, mulmod(state1, M11, F)), mulmod(state2, M21, F))
      )
      let scratch2 := add(
        0x0319d062072bef7ecca5eac06f97d4d55952c175ab6b03eae64b44c7dbf11cfa,
        add(add(14817777843080276494683266178512808687156649753153012854386334860566696099579, mulmod(state1, M12, F)), mulmod(state2, M22, F))
      )
      let state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := mulmod(scratch1, scratch1, F)
      scratch1 := mulmod(mulmod(state0, state0, F), scratch1, F)
      state0 := mulmod(scratch2, scratch2, F)
      scratch2 := mulmod(mulmod(state0, state0, F), scratch2, F)
      state0 := add(0x28813dcaebaeaa828a376df87af4a63bc8b7bf27ad49c6298ef7b387bf28526d, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x2727673b2ccbc903f181bf38e1c1d40d2033865200c352bc150928adddf9cb78, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x234ec45ca27727c2e74abd2b2a1494cd6efbd43e340587d6b8fb9e31e65cc632, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := mulmod(state1, state1, F)
      state1 := mulmod(mulmod(scratch0, scratch0, F), state1, F)
      scratch0 := mulmod(state2, state2, F)
      state2 := mulmod(mulmod(scratch0, scratch0, F), state2, F)
      scratch0 := add(0x15b52534031ae18f7f862cb2cf7cf760ab10a8150a337b1ccd99ff6e8797d428, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x0dc8fad6d9e4b35f5ed9a3d186b79ce38e0e8a8d1b58b132d701d4eecf68d1f6, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x1bcd95ffc211fbca600f705fad3fb567ea4eb378f62e1fec97805518a47e4d9c, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := mulmod(scratch1, scratch1, F)
      scratch1 := mulmod(mulmod(state0, state0, F), scratch1, F)
      state0 := mulmod(scratch2, scratch2, F)
      scratch2 := mulmod(mulmod(state0, state0, F), scratch2, F)
      state0 := add(0x10520b0ab721cadfe9eff81b016fc34dc76da36c2578937817cb978d069de559, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x1f6d48149b8e7f7d9b257d8ed5fbbaf42932498075fed0ace88a9eb81f5627f6, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x1d9655f652309014d29e00ef35a2089bfff8dc1c816f0dc9ca34bdb5460c8705, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x04df5a56ff95bcafb051f7b1cd43a99ba731ff67e47032058fe3d4185697cc7d, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x0672d995f8fff640151b3d290cedaf148690a10a8c8424a7f6ec282b6e4be828, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x099952b414884454b21200d7ffafdd5f0c9a9dcc06f2708e9fc1d8209b5c75b9, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x052cba2255dfd00c7c483143ba8d469448e43586a9b4cd9183fd0e843a6b9fa6, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x0b8badee690adb8eb0bd74712b7999af82de55707251ad7716077cb93c464ddc, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x119b1590f13307af5a1ee651020c07c749c15d60683a8050b963d0a8e4b2bdd1, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x03150b7cd6d5d17b2529d36be0f67b832c4acfc884ef4ee5ce15be0bfb4a8d09, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x2cc6182c5e14546e3cf1951f173912355374efb83d80898abe69cb317c9ea565, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x005032551e6378c450cfe129a404b3764218cadedac14e2b92d2cd73111bf0f9, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x233237e3289baa34bb147e972ebcb9516469c399fcc069fb88f9da2cc28276b5, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x05c8f4f4ebd4a6e3c980d31674bfbe6323037f21b34ae5a4e80c2d4c24d60280, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x0a7b1db13042d396ba05d818a319f25252bcf35ef3aeed91ee1f09b2590fc65b, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x2a73b71f9b210cf5b14296572c9d32dbf156e2b086ff47dc5df542365a404ec0, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x1ac9b0417abcc9a1935107e9ffc91dc3ec18f2c4dbe7f22976a760bb5c50c460, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x12c0339ae08374823fabb076707ef479269f3e4d6cb104349015ee046dc93fc0, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x0b7475b102a165ad7f5b18db4e1e704f52900aa3253baac68246682e56e9a28e, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x037c2849e191ca3edb1c5e49f6e8b8917c843e379366f2ea32ab3aa88d7f8448, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x05a6811f8556f014e92674661e217e9bd5206c5c93a07dc145fdb176a716346f, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x29a795e7d98028946e947b75d54e9f044076e87a7b2883b47b675ef5f38bd66e, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x20439a0c84b322eb45a3857afc18f5826e8c7382c8a1585c507be199981fd22f, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x2e0ba8d94d9ecf4a94ec2050c7371ff1bb50f27799a84b6d4a2a6f2a0982c887, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x143fd115ce08fb27ca38eb7cce822b4517822cd2109048d2e6d0ddcca17d71c8, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x0c64cbecb1c734b857968dbbdcf813cdf8611659323dbcbfc84323623be9caf1, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x028a305847c683f646fca925c163ff5ae74f348d62c2b670f1426cef9403da53, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x2e4ef510ff0b6fda5fa940ab4c4380f26a6bcb64d89427b824d6755b5db9e30c, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x0081c95bc43384e663d79270c956ce3b8925b4f6d033b078b96384f50579400e, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x2ed5f0c91cbd9749187e2fade687e05ee2491b349c039a0bba8a9f4023a0bb38, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x30509991f88da3504bbf374ed5aae2f03448a22c76234c8c990f01f33a735206, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x1c3f20fd55409a53221b7c4d49a356b9f0a1119fb2067b41a7529094424ec6ad, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x10b4e7f3ab5df003049514459b6e18eec46bb2213e8e131e170887b47ddcb96c, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x2a1982979c3ff7f43ddd543d891c2abddd80f804c077d775039aa3502e43adef, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x1c74ee64f15e1db6feddbead56d6d55dba431ebc396c9af95cad0f1315bd5c91, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x07533ec850ba7f98eab9303cace01b4b9e4f2e8b82708cfa9c2fe45a0ae146a0, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x21576b438e500449a151e4eeaf17b154285c68f42d42c1808a11abf3764c0750, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x2f17c0559b8fe79608ad5ca193d62f10bce8384c815f0906743d6930836d4a9e, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x2d477e3862d07708a79e8aae946170bc9775a4201318474ae665b0b1b7e2730e, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x162f5243967064c390e095577984f291afba2266c38f5abcd89be0f5b2747eab, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x2b4cb233ede9ba48264ecd2c8ae50d1ad7a8596a87f29f8a7777a70092393311, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x2c8fbcb2dd8573dc1dbaf8f4622854776db2eece6d85c4cf4254e7c35e03b07a, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x1d6f347725e4816af2ff453f0cd56b199e1b61e9f601e9ade5e88db870949da9, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x204b0c397f4ebe71ebc2d8b3df5b913df9e6ac02b68d31324cd49af5c4565529, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x0c4cb9dc3c4fd8174f1149b3c63c3c2f9ecb827cd7dc25534ff8fb75bc79c502, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x174ad61a1448c899a25416474f4930301e5c49475279e0639a616ddc45bc7b54, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x1a96177bcf4d8d89f759df4ec2f3cde2eaaa28c177cc0fa13a9816d49a38d2ef, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x066d04b24331d71cd0ef8054bc60c4ff05202c126a233c1a8242ace360b8a30a, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x2a4c4fc6ec0b0cf52195782871c6dd3b381cc65f72e02ad527037a62aa1bd804, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x13ab2d136ccf37d447e9f2e14a7cedc95e727f8446f6d9d7e55afc01219fd649, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x1121552fca26061619d24d843dc82769c1b04fcec26f55194c2e3e869acc6a9a, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x00ef653322b13d6c889bc81715c37d77a6cd267d595c4a8909a5546c7c97cff1, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x0e25483e45a665208b261d8ba74051e6400c776d652595d9845aca35d8a397d3, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x29f536dcb9dd7682245264659e15d88e395ac3d4dde92d8c46448db979eeba89, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x2a56ef9f2c53febadfda33575dbdbd885a124e2780bbea170e456baace0fa5be, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x1c8361c78eb5cf5decfb7a2d17b5c409f2ae2999a46762e8ee416240a8cb9af1, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x151aff5f38b20a0fc0473089aaf0206b83e8e68a764507bfd3d0ab4be74319c5, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x04c6187e41ed881dc1b239c88f7f9d43a9f52fc8c8b6cdd1e76e47615b51f100, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x13b37bd80f4d27fb10d84331f6fb6d534b81c61ed15776449e801b7ddc9c2967, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x01a5c536273c2d9df578bfbd32c17b7a2ce3664c2a52032c9321ceb1c4e8a8e4, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x2ab3561834ca73835ad05f5d7acb950b4a9a2c666b9726da832239065b7c3b02, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x1d4d8ec291e720db200fe6d686c0d613acaf6af4e95d3bf69f7ed516a597b646, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x041294d2cc484d228f5784fe7919fd2bb925351240a04b711514c9c80b65af1d, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x154ac98e01708c611c4fa715991f004898f57939d126e392042971dd90e81fc6, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x0b339d8acca7d4f83eedd84093aef51050b3684c88f8b0b04524563bc6ea4da4, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x0955e49e6610c94254a4f84cfbab344598f0e71eaff4a7dd81ed95b50839c82e, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x06746a6156eba54426b9e22206f15abca9a6f41e6f535c6f3525401ea0654626, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x0f18f5a0ecd1423c496f3820c549c27838e5790e2bd0a196ac917c7ff32077fb, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x04f6eeca1751f7308ac59eff5beb261e4bb563583ede7bc92a738223d6f76e13, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x2b56973364c4c4f5c1a3ec4da3cdce038811eb116fb3e45bc1768d26fc0b3758, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x123769dd49d5b054dcd76b89804b1bcb8e1392b385716a5d83feb65d437f29ef, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x2147b424fc48c80a88ee52b91169aacea989f6446471150994257b2fb01c63e9, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x0fdc1f58548b85701a6c5505ea332a29647e6f34ad4243c2ea54ad897cebe54d, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x12373a8251fea004df68abcf0f7786d4bceff28c5dbbe0c3944f685cc0a0b1f2, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x21e4f4ea5f35f85bad7ea52ff742c9e8a642756b6af44203dd8a1f35c1a90035, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x16243916d69d2ca3dfb4722224d4c462b57366492f45e90d8a81934f1bc3b147, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x1efbe46dd7a578b4f66f9adbc88b4378abc21566e1a0453ca13a4159cac04ac2, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x07ea5e8537cf5dd08886020e23a7f387d468d5525be66f853b672cc96a88969a, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x05a8c4f9968b8aa3b7b478a30f9a5b63650f19a75e7ce11ca9fe16c0b76c00bc, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x20f057712cc21654fbfe59bd345e8dac3f7818c701b9c7882d9d57b72a32e83f, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x04a12ededa9dfd689672f8c67fee31636dcd8e88d01d49019bd90b33eb33db69, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x27e88d8c15f37dcee44f1e5425a51decbd136ce5091a6767e49ec9544ccd101a, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x2feed17b84285ed9b8a5c8c5e95a41f66e096619a7703223176c41ee433de4d1, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x1ed7cc76edf45c7c404241420f729cf394e5942911312a0d6972b8bd53aff2b8, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x15742e99b9bfa323157ff8c586f5660eac6783476144cdcadf2874be45466b1a, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x1aac285387f65e82c895fc6887ddf40577107454c6ec0317284f033f27d0c785, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x25851c3c845d4790f9ddadbdb6057357832e2e7a49775f71ec75a96554d67c77, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x15a5821565cc2ec2ce78457db197edf353b7ebba2c5523370ddccc3d9f146a67, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x2411d57a4813b9980efa7e31a1db5966dcf64f36044277502f15485f28c71727, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x002e6f8d6520cd4713e335b8c0b6d2e647e9a98e12f4cd2558828b5ef6cb4c9b, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x2ff7bc8f4380cde997da00b616b0fcd1af8f0e91e2fe1ed7398834609e0315d2, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x00b9831b948525595ee02724471bcd182e9521f6b7bb68f1e93be4febb0d3cbe, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x0a2f53768b8ebf6a86913b0e57c04e011ca408648a4743a87d77adbf0c9c3512, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x00248156142fd0373a479f91ff239e960f599ff7e94be69b7f2a290305e1198d, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x171d5620b87bfb1328cf8c02ab3f0c9a397196aa6a542c2350eb512a2b2bcda9, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x170a4f55536f7dc970087c7c10d6fad760c952172dd54dd99d1045e4ec34a808, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x29aba33f799fe66c2ef3134aea04336ecc37e38c1cd211ba482eca17e2dbfae1, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x1e9bc179a4fdd758fdd1bb1945088d47e70d114a03f6a0e8b5ba650369e64973, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x1dd269799b660fad58f7f4892dfb0b5afeaad869a9c4b44f9c9e1c43bdaf8f09, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x22cdbc8b70117ad1401181d02e15459e7ccd426fe869c7c95d1dd2cb0f24af38, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x0ef042e454771c533a9f57a55c503fcefd3150f52ed94a7cd5ba93b9c7dacefd, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x11609e06ad6c8fe2f287f3036037e8851318e8b08a0359a03b304ffca62e8284, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x1166d9e554616dba9e753eea427c17b7fecd58c076dfe42708b08f5b783aa9af, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x2de52989431a859593413026354413db177fbf4cd2ac0b56f855a888357ee466, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x3006eb4ffc7a85819a6da492f3a8ac1df51aee5b17b8e89d74bf01cf5f71e9ad, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x2af41fbb61ba8a80fdcf6fff9e3f6f422993fe8f0a4639f962344c8225145086, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x119e684de476155fe5a6b41a8ebc85db8718ab27889e85e781b214bace4827c3, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x1835b786e2e8925e188bea59ae363537b51248c23828f047cff784b97b3fd800, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x28201a34c594dfa34d794996c6433a20d152bac2a7905c926c40e285ab32eeb6, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x083efd7a27d1751094e80fefaf78b000864c82eb571187724a761f88c22cc4e7, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x0b6f88a3577199526158e61ceea27be811c16df7774dd8519e079564f61fd13b, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x0ec868e6d15e51d9644f66e1d6471a94589511ca00d29e1014390e6ee4254f5b, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x2af33e3f866771271ac0c9b3ed2e1142ecd3e74b939cd40d00d937ab84c98591, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x0b520211f904b5e7d09b5d961c6ace7734568c547dd6858b364ce5e47951f178, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x0b2d722d0919a1aad8db58f10062a92ea0c56ac4270e822cca228620188a1d40, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x1f790d4d7f8cf094d980ceb37c2453e957b54a9991ca38bbe0061d1ed6e562d4, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x0171eb95dfbf7d1eaea97cd385f780150885c16235a2a6a8da92ceb01e504233, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x0c2d0e3b5fd57549329bf6885da66b9b790b40defd2c8650762305381b168873, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x1162fb28689c27154e5a8228b4e72b377cbcafa589e283c35d3803054407a18d, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x2f1459b65dee441b64ad386a91e8310f282c5a92a89e19921623ef8249711bc0, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x1e6ff3216b688c3d996d74367d5cd4c1bc489d46754eb712c243f70d1b53cfbb, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x01ca8be73832b8d0681487d27d157802d741a6f36cdc2a0576881f9326478875, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x1f7735706ffe9fc586f976d5bdf223dc680286080b10cea00b9b5de315f9650e, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x2522b60f4ea3307640a0c2dce041fba921ac10a3d5f096ef4745ca838285f019, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x23f0bee001b1029d5255075ddc957f833418cad4f52b6c3f8ce16c235572575b, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x2bc1ae8b8ddbb81fcaac2d44555ed5685d142633e9df905f66d9401093082d59, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x0f9406b8296564a37304507b8dba3ed162371273a07b1fc98011fcd6ad72205f, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x2360a8eb0cc7defa67b72998de90714e17e75b174a52ee4acb126c8cd995f0a8, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x15871a5cddead976804c803cbaef255eb4815a5e96df8b006dcbbc2767f88948, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x193a56766998ee9e0a8652dd2f3b1da0362f4f54f72379544f957ccdeefb420f, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x2a394a43934f86982f9be56ff4fab1703b2e63c8ad334834e4309805e777ae0f, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x1859954cfeb8695f3e8b635dcb345192892cd11223443ba7b4166e8876c0d142, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x04e1181763050e58013444dbcb99f1902b11bc25d90bbdca408d3819f4fed32b, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x0fdb253dee83869d40c335ea64de8c5bb10eb82db08b5e8b1f5e5552bfd05f23, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x058cbe8a9a5027bdaa4efb623adead6275f08686f1c08984a9d7c5bae9b4f1c0, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x1382edce9971e186497eadb1aeb1f52b23b4b83bef023ab0d15228b4cceca59a, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x03464990f045c6ee0819ca51fd11b0be7f61b8eb99f14b77e1e6634601d9e8b5, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x23f7bfc8720dc296fff33b41f98ff83c6fcab4605db2eb5aaa5bc137aeb70a58, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x0a59a158e3eec2117e6e94e7f0e9decf18c3ffd5e1531a9219636158bbaf62f2, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x06ec54c80381c052b58bf23b312ffd3ce2c4eba065420af8f4c23ed0075fd07b, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x118872dc832e0eb5476b56648e867ec8b09340f7a7bcb1b4962f0ff9ed1f9d01, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x13d69fa127d834165ad5c7cba7ad59ed52e0b0f0e42d7fea95e1906b520921b1, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x169a177f63ea681270b1c6877a73d21bde143942fb71dc55fd8a49f19f10c77b, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x04ef51591c6ead97ef42f287adce40d93abeb032b922f66ffb7e9a5a7450544d, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x256e175a1dc079390ecd7ca703fb2e3b19ec61805d4f03ced5f45ee6dd0f69ec, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x30102d28636abd5fe5f2af412ff6004f75cc360d3205dd2da002813d3e2ceeb2, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x10998e42dfcd3bbf1c0714bc73eb1bf40443a3fa99bef4a31fd31be182fcc792, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x193edd8e9fcf3d7625fa7d24b598a1d89f3362eaf4d582efecad76f879e36860, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x18168afd34f2d915d0368ce80b7b3347d1c7a561ce611425f2664d7aa51f0b5d, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x29383c01ebd3b6ab0c017656ebe658b6a328ec77bc33626e29e2e95b33ea6111, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x10646d2f2603de39a1f4ae5e7771a64a702db6e86fb76ab600bf573f9010c711, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x0beb5e07d1b27145f575f1395a55bf132f90c25b40da7b3864d0242dcb1117fb, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x16d685252078c133dc0d3ecad62b5c8830f95bb2e54b59abdffbf018d96fa336, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x0a6abd1d833938f33c74154e0404b4b40a555bbbec21ddfafd672dd62047f01a, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x1a679f5d36eb7b5c8ea12a4c2dedc8feb12dffeec450317270a6f19b34cf1860, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x0980fb233bd456c23974d50e0ebfde4726a423eada4e8f6ffbc7592e3f1b93d6, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x161b42232e61b84cbf1810af93a38fc0cece3d5628c9282003ebacb5c312c72b, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x0ada10a90c7f0520950f7d47a60d5e6a493f09787f1564e5d09203db47de1a0b, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x1a730d372310ba82320345a29ac4238ed3f07a8a2b4e121bb50ddb9af407f451, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x2c8120f268ef054f817064c369dda7ea908377feaba5c4dffbda10ef58e8c556, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x1c7c8824f758753fa57c00789c684217b930e95313bcb73e6e7b8649a4968f70, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x2cd9ed31f5f8691c8e39e4077a74faa0f400ad8b491eb3f7b47b27fa3fd1cf77, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x23ff4f9d46813457cf60d92f57618399a5e022ac321ca550854ae23918a22eea, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x09945a5d147a4f66ceece6405dddd9d0af5a2c5103529407dff1ea58f180426d, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x188d9c528025d4c2b67660c6b771b90f7c7da6eaa29d3f268a6dd223ec6fc630, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x3050e37996596b7f81f68311431d8734dba7d926d3633595e0c0d8ddf4f0f47f, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x15af1169396830a91600ca8102c35c426ceae5461e3f95d89d829518d30afd78, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x1da6d09885432ea9a06d9f37f873d985dae933e351466b2904284da3320d8acc, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := add(0x2796ea90d269af29f5f8acf33921124e4e4fad3dbe658945e546ee411ddaa9cb, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x202d7dd1da0f6b4b0325c8b3307742f01e15612ec8e9304a7cb0319e01d32d60, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x096d6790d05bb759156a952ba263d672a2d7f9c788f4c831a29dace4c0f8be5f, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := add(0x054efa1f65b0fce283808965275d877b438da23ce5b13e1963798cb1447d25a4, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x1b162f83d917e93edb3308c29802deb9d8aa690113b2e14864ccf6e18e4165f1, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x21e5241e12564dd6fd9f1cdd2a0de39eedfefc1466cc568ec5ceb745a0506edc, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := mulmod(scratch1, scratch1, F)
      scratch1 := mulmod(mulmod(state0, state0, F), scratch1, F)
      state0 := mulmod(scratch2, scratch2, F)
      scratch2 := mulmod(mulmod(state0, state0, F), scratch2, F)
      state0 := add(0x1cfb5662e8cf5ac9226a80ee17b36abecb73ab5f87e161927b4349e10e4bdf08, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x0f21177e302a771bbae6d8d1ecb373b62c99af346220ac0129c53f666eb24100, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x1671522374606992affb0dd7f71b12bec4236aede6290546bcef7e1f515c2320, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := mulmod(state1, state1, F)
      state1 := mulmod(mulmod(scratch0, scratch0, F), state1, F)
      scratch0 := mulmod(state2, state2, F)
      state2 := mulmod(mulmod(scratch0, scratch0, F), state2, F)
      scratch0 := add(0x0fa3ec5b9488259c2eb4cf24501bfad9be2ec9e42c5cc8ccd419d2a692cad870, add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)))
      scratch1 := add(0x193c0e04e0bd298357cb266c1506080ed36edce85c648cc085e8c57b1ab54bba, add(add(mulmod(state0, M01, F), mulmod(state1, M11, F)), mulmod(state2, M21, F)))
      scratch2 := add(0x102adf8ef74735a27e9128306dcbc3c99f6f7291cd406578ce14ea2adaba68f8, add(add(mulmod(state0, M02, F), mulmod(state1, M12, F)), mulmod(state2, M22, F)))
      state0 := mulmod(scratch0, scratch0, F)
      scratch0 := mulmod(mulmod(state0, state0, F), scratch0, F)
      state0 := mulmod(scratch1, scratch1, F)
      scratch1 := mulmod(mulmod(state0, state0, F), scratch1, F)
      state0 := mulmod(scratch2, scratch2, F)
      scratch2 := mulmod(mulmod(state0, state0, F), scratch2, F)
      state0 := add(0x0fe0af7858e49859e2a54d6f1ad945b1316aa24bfbdd23ae40a6d0cb70c3eab1, add(add(mulmod(scratch0, M00, F), mulmod(scratch1, M10, F)), mulmod(scratch2, M20, F)))
      state1 := add(0x216f6717bbc7dedb08536a2220843f4e2da5f1daa9ebdefde8a5ea7344798d22, add(add(mulmod(scratch0, M01, F), mulmod(scratch1, M11, F)), mulmod(scratch2, M21, F)))
      state2 := add(0x1da55cc900f0d21f4a3e694391918a1b3c23b2ac773c6b3ef88e2e4228325161, add(add(mulmod(scratch0, M02, F), mulmod(scratch1, M12, F)), mulmod(scratch2, M22, F)))
      scratch0 := mulmod(state0, state0, F)
      state0 := mulmod(mulmod(scratch0, scratch0, F), state0, F)
      scratch0 := mulmod(state1, state1, F)
      state1 := mulmod(mulmod(scratch0, scratch0, F), state1, F)
      scratch0 := mulmod(state2, state2, F)
      state2 := mulmod(mulmod(scratch0, scratch0, F), state2, F)

      mstore(0x0, mod(add(add(mulmod(state0, M00, F), mulmod(state1, M10, F)), mulmod(state2, M20, F)), F))

      return(0, 0x20)
    }
  }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

/**
 * @title IPoseidonT3
 * @notice Interface for the PoseidonT3 library
 */
interface IPoseidonT3 {
    function hash(uint256[2] memory inputs) external pure returns (uint256);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

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

/**
 * @title Circuit Constants Library
 * @notice This library defines constants representing indices used to access public signals
 *         of various circuits such as register, DSC, and VC/Disclose.
 * @dev These indices map directly to specific data fields in the corresponding circuits proofs.
 */
library CircuitConstantsV2 {
    // ---------------------------
    // Register Circuit Constants
    // ---------------------------

    /**
     * @notice Index to access the nullifier in the register circuit public signals.
     */
    uint256 constant REGISTER_NULLIFIER_INDEX = 0;

    /**
     * @notice Index to access the commitment in the register circuit public signals.
     */
    uint256 constant REGISTER_COMMITMENT_INDEX = 1;

    /**
     * @notice Index to access the Merkle root in the register circuit public signals.
     */
    uint256 constant REGISTER_MERKLE_ROOT_INDEX = 2;

    // ---------------------------
    // DSC Circuit Constants
    // ---------------------------

    /**
     * @notice Index to access the tree leaf in the DSC circuit public signals.
     */
    uint256 constant DSC_TREE_LEAF_INDEX = 0;

    /**
     * @notice Index to access the CSCA root in the DSC circuit public signals.
     */
    uint256 constant DSC_CSCA_ROOT_INDEX = 1;

    // ---------------------------
    // Aadhaar Circuit Constants
    // ---------------------------
    /**
     * @notice Index to access the pubkey commitment in the Aadhaar circuit public signals.
     */
    uint256 constant AADHAAR_UIDAI_PUBKEY_COMMITMENT_INDEX = 0;
    uint256 constant AADHAAR_NULLIFIER_INDEX = 1;
    uint256 constant AADHAAR_COMMITMENT_INDEX = 2;
    uint256 constant AADHAAR_TIMESTAMP_INDEX = 3;

    // -------------------------------------
    // VC and Disclose Circuit Constants
    // -------------------------------------

    /**
     * @notice Structure containing circuit indices for a specific attestation type.
     */
    struct DiscloseIndices {
        uint256 revealedDataPackedIndex;
        uint256 forbiddenCountriesListPackedIndex;
        uint256 nullifierIndex;
        uint256 attestationIdIndex;
        uint256 merkleRootIndex;
        uint256 currentDateIndex;
        uint256 namedobSmtRootIndex;
        uint256 nameyobSmtRootIndex;
        uint256 scopeIndex;
        uint256 userIdentifierIndex;
        uint256 passportNoSmtRootIndex;
    }

    /**
     * @notice Returns the circuit indices for a given attestation type.
     * @param attestationId The attestation identifier.
     * @return indices The DiscloseIndices struct containing all relevant indices.
     */
    function getDiscloseIndices(bytes32 attestationId) internal pure returns (DiscloseIndices memory indices) {
        if (attestationId == AttestationId.E_PASSPORT) {
            return
                DiscloseIndices({
                    revealedDataPackedIndex: 0,
                    forbiddenCountriesListPackedIndex: 3,
                    nullifierIndex: 7,
                    attestationIdIndex: 8,
                    merkleRootIndex: 9,
                    currentDateIndex: 10,
                    namedobSmtRootIndex: 17,
                    nameyobSmtRootIndex: 18,
                    scopeIndex: 19,
                    userIdentifierIndex: 20,
                    passportNoSmtRootIndex: 16
                });
        } else if (attestationId == AttestationId.EU_ID_CARD) {
            return
                DiscloseIndices({
                    revealedDataPackedIndex: 0,
                    forbiddenCountriesListPackedIndex: 4,
                    nullifierIndex: 8,
                    attestationIdIndex: 9,
                    merkleRootIndex: 10,
                    currentDateIndex: 11,
                    namedobSmtRootIndex: 17,
                    nameyobSmtRootIndex: 18,
                    scopeIndex: 19,
                    userIdentifierIndex: 20,
                    passportNoSmtRootIndex: 99
                });
        } else if (attestationId == AttestationId.AADHAAR) {
            return
                DiscloseIndices({
                    revealedDataPackedIndex: 2,
                    forbiddenCountriesListPackedIndex: 6,
                    nullifierIndex: 0,
                    attestationIdIndex: 10,
                    merkleRootIndex: 16,
                    currentDateIndex: 11,
                    namedobSmtRootIndex: 14,
                    nameyobSmtRootIndex: 15,
                    scopeIndex: 17,
                    userIdentifierIndex: 18,
                    passportNoSmtRootIndex: 99
                });
        } else {
            revert("Invalid attestation ID");
        }
    }
}

File 17 of 24 : AttestationId.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

/**
 * @title AttestationId Library
 * @notice This library provides attestation identifiers used across contracts.
 * @dev Currently, it contains the constant E_PASSPORT which represents the identifier
 * for an E-PASSPORT attestation computed as Poseidon("E-PASSPORT").
 */
library AttestationId {
    /**
     * @notice Identifier for an E-PASSPORT attestation.
     * @dev The identifier is computed based on the hash of "E-PASSPORT" using the Poseidon hash function.
     * Here it is hardcoded as bytes32(uint256(1)) for demonstration purposes.
     */
    bytes32 constant E_PASSPORT = bytes32(uint256(1));
    bytes32 constant EU_ID_CARD = bytes32(uint256(2));
    bytes32 constant AADHAAR = bytes32(uint256(3));
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

/**
 * @title Formatter Library
 * @notice A library providing utility functions to format names, dates, and encode data.
 */
library Formatter {
    error InvalidDateLength();
    error InvalidYearRange();
    error InvalidMonthRange();
    error InvalidDayRange();
    error InvalidFieldElement();
    error InvalidDateDigit();

    uint256 constant MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH = 40;
    uint256 constant SNARK_SCALAR_FIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617;

    /**
     * @notice Formats a full name string into first name(s) and last name.
     * @dev The input is expected to contain a last name, followed by a "<<" separator and then first name(s).
     *      The returned array contains the first names at index 0 and the last name at index 1.
     * @param input The input string structured as "lastName<<firstName(s)".
     * @return names An array of two strings: [firstName(s), lastName].
     */
    function formatName(string memory input) internal pure returns (string[] memory) {
        bytes memory inputBytes = bytes(input);
        bytes memory firstNameBytes;
        bytes memory lastNameBytes;
        string[] memory names = new string[](2);

        uint256 i = 0;
        // Extract last name
        while (i < inputBytes.length && inputBytes[i] != "<") {
            lastNameBytes = abi.encodePacked(lastNameBytes, inputBytes[i]);
            i++;
        }

        // Skip the separator "<<".
        i += 2;

        // Extract first names.
        while (i < inputBytes.length) {
            if (inputBytes[i] == "<") {
                if (i + 1 < inputBytes.length && inputBytes[i + 1] == "<") {
                    break;
                }
                firstNameBytes = abi.encodePacked(firstNameBytes, " ");
            } else {
                firstNameBytes = abi.encodePacked(firstNameBytes, inputBytes[i]);
            }
            i++;
        }

        names[0] = string(firstNameBytes);
        names[1] = string(lastNameBytes);
        return names;
    }

    /**
     * @notice Formats a compact date string into a human-readable date.
     * @dev Expects the input date string to have exactly 6 characters in YYMMDD format.
     *      Returns the date in "DD-MM-YY" format.
     * @param date A string representing the date in YYMMDD format.
     * @return A formatted date string in the format "DD-MM-YY".
     */
    function formatDate(string memory date) internal pure returns (string memory) {
        bytes memory dateBytes = bytes(date);
        if (dateBytes.length != 6) {
            revert InvalidDateLength();
        }

        if (dateBytes[2] > "1" || (dateBytes[2] == "1" && dateBytes[3] > "2")) {
            revert InvalidMonthRange();
        }

        if (dateBytes[4] > "3" || (dateBytes[4] == "3" && dateBytes[5] > "1")) {
            revert InvalidDayRange();
        }

        string memory year = substring(date, 0, 2);
        string memory month = substring(date, 2, 4);
        string memory day = substring(date, 4, 6);

        return string(abi.encodePacked(day, "-", month, "-", year));
    }

    /**
     * @notice Formats a full year date string into a human-readable date.
     * @dev Expects the input date string to have exactly 8 characters in YYYYMMDD format.
     *      Returns the date in "YYYY-MM-DD" format.
     * @param date A string representing the date in YYYYMMDD format.
     * @return A formatted date string in the format "YYYY-MM-DD".
     */
    function formatDateFullYear(string memory date) internal pure returns (string memory) {
        bytes memory dateBytes = bytes(date);
        if (dateBytes.length != 8) {
            revert InvalidDateLength();
        }

        if (dateBytes[4] > "1" || (dateBytes[4] == "1" && dateBytes[5] > "2")) {
            revert InvalidMonthRange();
        }

        if (dateBytes[6] > "3" || (dateBytes[6] == "3" && dateBytes[7] > "1")) {
            revert InvalidDayRange();
        }

        string memory year = substring(date, 0, 4);
        string memory month = substring(date, 4, 6);
        string memory day = substring(date, 6, 8);

        return string(abi.encodePacked(day, "-", month, "-", year));
    }

    /**
     * @notice Converts an ASCII numeral code to its corresponding unsigned integer.
     * @dev The input must represent an ASCII code for digits (0-9), i.e. between 48 and 57.
     *      Reverts with InvalidAsciiCode if the input is out of range.
     * @param numAscii The ASCII code of a digit character.
     * @return The numeric value (0-9) corresponding to the ASCII code.
     */
    function numAsciiToUint(uint256 numAscii) internal pure returns (uint256) {
        return (numAscii - 48);
    }

    /**
     * @notice Converts an array of three field elements into a bytes representation.
     * @dev Each element is converted into a specific number of bytes: 31, 31, and 31 respectively.
     * @param publicSignals An array of three unsigned integers representing field elements.
     * @return bytesArray A bytes array of total length 93 that encodes the three field elements.
     */
    function fieldElementsToBytes(uint256[3] memory publicSignals) internal pure returns (bytes memory) {
        if (
            publicSignals[0] >= SNARK_SCALAR_FIELD ||
            publicSignals[1] >= SNARK_SCALAR_FIELD ||
            publicSignals[2] >= SNARK_SCALAR_FIELD
        ) {
            revert InvalidFieldElement();
        }
        uint8[3] memory bytesCount = [31, 31, 31];
        bytes memory bytesArray = new bytes(93);

        uint256 index = 0;
        for (uint256 i = 0; i < 3; i++) {
            uint256 element = publicSignals[i];
            for (uint8 j = 0; j < bytesCount[i]; j++) {
                bytesArray[index++] = bytes1(uint8(element & 0xff));
                element = element >> 8;
            }
        }
        return bytesArray;
    }

    function fieldElementsToBytesIdCard(uint256[4] memory publicSignals) internal pure returns (bytes memory) {
        if (
            publicSignals[0] >= SNARK_SCALAR_FIELD ||
            publicSignals[1] >= SNARK_SCALAR_FIELD ||
            publicSignals[2] >= SNARK_SCALAR_FIELD ||
            publicSignals[3] >= SNARK_SCALAR_FIELD
        ) {
            revert InvalidFieldElement();
        }
        uint8[4] memory bytesCount = [31, 31, 31, 1];
        bytes memory bytesArray = new bytes(94);

        uint256 index = 0;
        for (uint256 i = 0; i < 4; i++) {
            uint256 element = publicSignals[i];
            for (uint8 j = 0; j < bytesCount[i]; j++) {
                bytesArray[index++] = bytes1(uint8(element & 0xff));
                element = element >> 8;
            }
        }
        return bytesArray;
    }

    function fieldElementsToBytesAadhaar(uint256[4] memory publicSignals) internal pure returns (bytes memory) {
        for (uint256 i = 0; i < 4; i++) {
            if (publicSignals[i] >= SNARK_SCALAR_FIELD) {
                revert InvalidFieldElement();
            }
        }

        uint8[4] memory bytesCount = [31, 31, 31, 26];
        bytes memory bytesArray = new bytes(119);

        uint256 index = 0;
        for (uint256 i = 0; i < 4; i++) {
            uint256 element = publicSignals[i];
            for (uint8 j = 0; j < bytesCount[i]; j++) {
                bytesArray[index++] = bytes1(uint8(element & 0xff));
                element = element >> 8;
            }
        }

        return bytesArray;
    }

    /**
     * @notice Extracts forbidden country codes from a packed uint256.
     * @dev Each forbidden country is represented by 3 bytes in the packed data.
     *      The function extracts up to MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH forbidden countries.
     * @param publicSignals A packed uint256 containing encoded forbidden country data.
     * @return forbiddenCountries An array of strings representing the forbidden country codes.
     */
    function extractForbiddenCountriesFromPacked(
        uint256[4] memory publicSignals
    ) internal pure returns (string[MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH] memory forbiddenCountries) {
        for (uint256 i = 0; i < 4; i++) {
            if (publicSignals[i] >= SNARK_SCALAR_FIELD) {
                revert InvalidFieldElement();
            }
        }

        for (uint256 j = 0; j < MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH; j++) {
            uint256 byteIndex = (j * 3) % 93;
            uint256 index = j / 31;

            if (byteIndex + 2 < 31) {
                uint256 shift = byteIndex * 8;
                uint256 mask = 0xFFFFFF;
                uint256 packedData = (publicSignals[index * 3] >> shift) & mask;
                uint256 reversedPackedData = ((packedData & 0xff) << 16) |
                    ((packedData & 0xff00)) |
                    ((packedData & 0xff0000) >> 16);
                forbiddenCountries[j] = string(abi.encodePacked(uint24(reversedPackedData)));
            } else if (byteIndex < 31) {
                uint256 part0 = (publicSignals[0] >> (byteIndex * 8));
                uint256 part1 = publicSignals[1] & 0x00ffff;
                uint256 reversedPart1 = ((part1 & 0xff) << 8) | ((part1 & 0xff00) >> 8);
                uint256 combined = reversedPart1 | (part0 << 16);
                forbiddenCountries[j] = string(abi.encodePacked(uint24(combined)));
            } else if (byteIndex + 2 < 62) {
                uint256 byteIndexIn1 = byteIndex - 31;
                uint256 shift = byteIndexIn1 * 8;
                uint256 mask = 0xFFFFFF;
                uint256 packedData = (publicSignals[1] >> shift) & mask;
                uint256 reversedPackedData = ((packedData & 0xff) << 16) |
                    ((packedData & 0xff00)) |
                    ((packedData & 0xff0000) >> 16);
                forbiddenCountries[j] = string(abi.encodePacked(uint24(reversedPackedData)));
            } else if (byteIndex < 62) {
                uint256 part0 = (publicSignals[1] >> ((byteIndex - 31) * 8)) & 0x00ffff;
                uint256 reversedPart0 = ((part0 & 0xff) << 8) | ((part0 & 0xff00) >> 8);
                uint256 part1 = publicSignals[2] & 0x0000ff;
                uint256 combined = part1 | (reversedPart0 << 8);
                forbiddenCountries[j] = string(abi.encodePacked(uint24(combined)));
            } else if (byteIndex < 93) {
                uint256 byteIndexIn1 = byteIndex - 62;
                uint256 shift = byteIndexIn1 * 8;
                uint256 mask = 0xFFFFFF;
                uint256 packedData = (publicSignals[2] >> shift) & mask;
                uint256 reversedPackedData = ((packedData & 0xff) << 16) |
                    ((packedData & 0xff00)) |
                    ((packedData & 0xff0000) >> 16);
                forbiddenCountries[j] = string(abi.encodePacked(uint24(reversedPackedData)));
            }
        }

        return forbiddenCountries;
    }

    /**
     * @notice Converts an array of 6 numerical values representing a date into a Unix timestamp.
     * @dev Each element in the dateNum array is taken modulo 10, converted to its ASCII digit,
     *      and concatenated to form a date string in YYMMDD format. This string is then converted
     *      into a Unix timestamp using dateToUnixTimestamp.
     * @param dateNum An array of 6 unsigned integers representing a date in YYMMDD format.
     * @return timestamp The Unix timestamp corresponding to the provided date.
     */
    function proofDateToUnixTimestamp(uint256[6] memory dateNum) internal pure returns (uint256) {
        for (uint256 i = 0; i < 6; i++) {
            if (dateNum[i] > 9) {
                revert InvalidDateDigit();
            }
        }
        string memory date = "";
        for (uint256 i = 0; i < 6; i++) {
            date = string(abi.encodePacked(date, bytes1(uint8(48 + (dateNum[i] % 10)))));
        }
        uint256 currentTimestamp = dateToUnixTimestamp(date);
        return currentTimestamp;
    }

    /**
     * @notice Converts an array of 3 numerical values representing a date into a Unix timestamp.
     * @dev The input is expected to be in the format [year, month, day] and is not padded with 0s.
     * @param dateNum An array of 3 unsigned integers representing a date in YYMMDD format.
     * @return timestamp The Unix timestamp corresponding to the provided date.
     */
    function proofDateToUnixTimestampNumeric(uint256[3] memory dateNum) internal pure returns (uint256) {
        if (dateNum[1] > 12 || dateNum[2] > 31) {
            revert InvalidDateDigit();
        }
        return toTimestamp(dateNum[0], dateNum[1], dateNum[2]);
    }

    /**
     * @notice Converts a date string in YYMMDD format into a Unix timestamp.
     * @dev Parses the date string by extracting year, month, and day components using substring,
     *      converts each component to an integer, and then computes the timestamp via toTimestamp.
     *      Reverts if the input string is not exactly 6 characters long.
     * @param date A 6-character string representing the date in YYMMDD format.
     * @return timestamp The Unix timestamp corresponding to the input date.
     */
    function dateToUnixTimestamp(string memory date) internal pure returns (uint256) {
        bytes memory dateBytes = bytes(date);
        if (dateBytes.length != 6) {
            revert InvalidDateLength();
        }

        if (dateBytes[2] > "1" || (dateBytes[2] == "1" && dateBytes[3] > "2")) {
            revert InvalidMonthRange();
        }

        if (dateBytes[4] > "3" || (dateBytes[4] == "3" && dateBytes[5] > "1")) {
            revert InvalidDayRange();
        }

        uint256 year = parseDatePart(substring(date, 0, 2)) + 2000;
        uint256 month = parseDatePart(substring(date, 2, 4));
        uint256 day = parseDatePart(substring(date, 4, 6));

        return toTimestamp(year, month, day);
    }

    /**
     * @notice Extracts a substring from a given string.
     * @dev Returns the substring from startIndex (inclusive) to endIndex (exclusive).
     * @param str The input string.
     * @param startIndex The starting index of the substring (inclusive).
     * @param endIndex The ending index of the substring (exclusive).
     * @return The resulting substring.
     */
    function substring(string memory str, uint256 startIndex, uint256 endIndex) internal pure returns (string memory) {
        bytes memory strBytes = bytes(str);
        bytes memory result = new bytes(endIndex - startIndex);

        for (uint256 i = startIndex; i < endIndex; i++) {
            result[i - startIndex] = strBytes[i];
        }

        return string(result);
    }

    /**
     * @notice Parses a numeric string and returns its unsigned integer representation.
     * @dev Assumes the input string contains only numeric characters.
     * @param value The string representing a number.
     * @return result The parsed unsigned integer.
     */
    function parseDatePart(string memory value) internal pure returns (uint256) {
        bytes memory tempEmptyStringTest = bytes(value);
        if (tempEmptyStringTest.length == 0) {
            return 0;
        }

        uint256 digit;
        uint256 result;
        for (uint256 i = 0; i < tempEmptyStringTest.length; i++) {
            digit = uint8(tempEmptyStringTest[i]) - 48;
            result = result * 10 + digit;
        }
        return result;
    }

    /**
     * @notice Converts a specific date into a Unix timestamp.
     * @dev Calculates the timestamp by summing the number of days for years, months, and days since January 1, 1970.
     *      Takes leap years into account during the calculation.
     * @param year The full year (e.g., 2023).
     * @param month The month (1-12).
     * @param day The day of the month.
     * @return timestamp The Unix timestamp corresponding to the given date.
     */
    function toTimestamp(uint256 year, uint256 month, uint256 day) internal pure returns (uint256 timestamp) {
        uint16 i;

        if (year < 1970 || year > 2100) {
            revert InvalidYearRange();
        }

        if (month < 1 || month > 12) {
            revert InvalidMonthRange();
        }

        // Year.
        for (i = 1970; i < year; i++) {
            if (isLeapYear(i)) {
                timestamp += 366 days;
            } else {
                timestamp += 365 days;
            }
        }

        // Month.
        uint8[12] memory monthDayCounts;
        monthDayCounts[0] = 31;
        if (isLeapYear(year)) {
            monthDayCounts[1] = 29;
        } else {
            monthDayCounts[1] = 28;
        }
        monthDayCounts[2] = 31;
        monthDayCounts[3] = 30;
        monthDayCounts[4] = 31;
        monthDayCounts[5] = 30;
        monthDayCounts[6] = 31;
        monthDayCounts[7] = 31;
        monthDayCounts[8] = 30;
        monthDayCounts[9] = 31;
        monthDayCounts[10] = 30;
        monthDayCounts[11] = 31;

        if (day < 1 || day > monthDayCounts[month - 1]) {
            revert InvalidDayRange();
        }

        for (i = 1; i < month; i++) {
            timestamp += monthDayCounts[i - 1] * 1 days;
        }

        // Day.
        timestamp += (day - 1) * 1 days;

        return timestamp;
    }

    /**
     * @notice Checks whether a given year is a leap year.
     * @param year The year to check.
     * @return True if the year is a leap year, otherwise false.
     */
    function isLeapYear(uint256 year) internal pure returns (bool) {
        if (year < 1970 || year > 2100) {
            revert InvalidYearRange();
        }

        if (year % 4 != 0) {
            return false;
        } else if (year % 100 != 0) {
            return true;
        } else if (year % 400 != 0) {
            return false;
        } else {
            return true;
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
/**
 * @title IRegisterCircuitVerifier
 * @notice Interface for verifying register circuit proofs.
 * @dev This interface defines the structure of a register circuit proof and exposes a function to verify such proofs.
 */

struct GenericProofStruct {
    uint256[2] a;
    uint256[2][2] b;
    uint256[2] c;
    uint256[] pubSignals;
}

interface IRegisterCircuitVerifier {
    /**
     * @notice Represents a register circuit proof.
     * @dev This structure encapsulates the required proof elements.
     * @param a An array of two unsigned integers representing the proof component 'a'.
     * @param b A 2x2 array of unsigned integers representing the proof component 'b'.
     * @param c An array of two unsigned integers representing the proof component 'c'.
     * @param pubSignals An array of three unsigned integers representing the public signals associated with the proof.
     */
    struct RegisterCircuitProof {
        uint256[2] a;
        uint256[2][2] b;
        uint256[2] c;
        uint256[3] pubSignals;
    }

    /**
     * @notice Verifies a given register circuit proof.
     * @dev This function checks the validity of the provided proof parameters.
     * @param a The 'a' component of the proof.
     * @param b The 'b' component of the proof.
     * @param c The 'c' component of the proof.
     * @param pubSignals The public signals associated with the proof.
     * @return isValid A boolean value indicating whether the provided proof is valid (true) or not (false).
     */
    function verifyProof(
        uint256[2] calldata a,
        uint256[2][2] calldata b,
        uint256[2] calldata c,
        uint256[3] calldata pubSignals
    ) external view returns (bool isValid);
}

interface IAadhaarRegisterCircuitVerifier {
    /**
     * @notice Verifies a given register circuit proof.
     * @dev This function checks the validity of the provided proof parameters.
     * @param a The 'a' component of the proof.
     * @param b The 'b' component of the proof.
     * @param c The 'c' component of the proof.
     * @param pubSignals The public signals associated with the proof.
     * @return isValid A boolean value indicating whether the provided proof is valid (true) or not (false).
     */
    function verifyProof(
        uint256[2] calldata a,
        uint256[2][2] calldata b,
        uint256[2] calldata c,
        uint256[4] calldata pubSignals
    ) external view returns (bool isValid);
}

File 20 of 24 : IDscCircuitVerifier.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

/**
 * @title IDscCircuitVerifier
 * @notice Interface for verifying zero-knowledge proofs related to the DSC circuit.
 * @dev This interface defines the structure of a DSC circuit proof and exposes a function to verify such proofs.
 */
interface IDscCircuitVerifier {
    /**
     * @notice Represents a DSC circuit proof.
     * @param a An array of two unsigned integers representing the proof component 'a'.
     * @param b A 2x2 array of unsigned integers representing the proof component 'b'.
     * @param c An array of two unsigned integers representing the proof component 'c'.
     * @param pubSignals An array of two unsigned integers representing the public signals associated with the proof.
     */
    struct DscCircuitProof {
        uint256[2] a;
        uint256[2][2] b;
        uint256[2] c;
        uint256[2] pubSignals;
    }

    /**
     * @notice Verifies a given DSC circuit zero-knowledge proof.
     * @dev This function checks the validity of the provided DSC proof parameters.
     * @param pA The 'a' component of the proof.
     * @param pB The 'b' component of the proof.
     * @param pC The 'c' component of the proof.
     * @param pubSignals The public signals associated with the proof.
     * @return A boolean value indicating whether the provided proof is valid (true) or not (false).
     */
    function verifyProof(
        uint256[2] calldata pA,
        uint256[2][2] calldata pB,
        uint256[2] calldata pC,
        uint256[2] calldata pubSignals
    ) external view returns (bool);
}

File 21 of 24 : SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.

pragma solidity ^0.8.20;

/**
 * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeCast {
    /**
     * @dev Value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);

    /**
     * @dev An int value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedIntToUint(int256 value);

    /**
     * @dev Value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);

    /**
     * @dev An uint value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedUintToInt(uint256 value);

    /**
     * @dev Returns the downcasted uint248 from uint256, reverting on
     * overflow (when the input is greater than largest uint248).
     *
     * Counterpart to Solidity's `uint248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toUint248(uint256 value) internal pure returns (uint248) {
        if (value > type(uint248).max) {
            revert SafeCastOverflowedUintDowncast(248, value);
        }
        return uint248(value);
    }

    /**
     * @dev Returns the downcasted uint240 from uint256, reverting on
     * overflow (when the input is greater than largest uint240).
     *
     * Counterpart to Solidity's `uint240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toUint240(uint256 value) internal pure returns (uint240) {
        if (value > type(uint240).max) {
            revert SafeCastOverflowedUintDowncast(240, value);
        }
        return uint240(value);
    }

    /**
     * @dev Returns the downcasted uint232 from uint256, reverting on
     * overflow (when the input is greater than largest uint232).
     *
     * Counterpart to Solidity's `uint232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toUint232(uint256 value) internal pure returns (uint232) {
        if (value > type(uint232).max) {
            revert SafeCastOverflowedUintDowncast(232, value);
        }
        return uint232(value);
    }

    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        if (value > type(uint224).max) {
            revert SafeCastOverflowedUintDowncast(224, value);
        }
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint216 from uint256, reverting on
     * overflow (when the input is greater than largest uint216).
     *
     * Counterpart to Solidity's `uint216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toUint216(uint256 value) internal pure returns (uint216) {
        if (value > type(uint216).max) {
            revert SafeCastOverflowedUintDowncast(216, value);
        }
        return uint216(value);
    }

    /**
     * @dev Returns the downcasted uint208 from uint256, reverting on
     * overflow (when the input is greater than largest uint208).
     *
     * Counterpart to Solidity's `uint208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toUint208(uint256 value) internal pure returns (uint208) {
        if (value > type(uint208).max) {
            revert SafeCastOverflowedUintDowncast(208, value);
        }
        return uint208(value);
    }

    /**
     * @dev Returns the downcasted uint200 from uint256, reverting on
     * overflow (when the input is greater than largest uint200).
     *
     * Counterpart to Solidity's `uint200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toUint200(uint256 value) internal pure returns (uint200) {
        if (value > type(uint200).max) {
            revert SafeCastOverflowedUintDowncast(200, value);
        }
        return uint200(value);
    }

    /**
     * @dev Returns the downcasted uint192 from uint256, reverting on
     * overflow (when the input is greater than largest uint192).
     *
     * Counterpart to Solidity's `uint192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toUint192(uint256 value) internal pure returns (uint192) {
        if (value > type(uint192).max) {
            revert SafeCastOverflowedUintDowncast(192, value);
        }
        return uint192(value);
    }

    /**
     * @dev Returns the downcasted uint184 from uint256, reverting on
     * overflow (when the input is greater than largest uint184).
     *
     * Counterpart to Solidity's `uint184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toUint184(uint256 value) internal pure returns (uint184) {
        if (value > type(uint184).max) {
            revert SafeCastOverflowedUintDowncast(184, value);
        }
        return uint184(value);
    }

    /**
     * @dev Returns the downcasted uint176 from uint256, reverting on
     * overflow (when the input is greater than largest uint176).
     *
     * Counterpart to Solidity's `uint176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toUint176(uint256 value) internal pure returns (uint176) {
        if (value > type(uint176).max) {
            revert SafeCastOverflowedUintDowncast(176, value);
        }
        return uint176(value);
    }

    /**
     * @dev Returns the downcasted uint168 from uint256, reverting on
     * overflow (when the input is greater than largest uint168).
     *
     * Counterpart to Solidity's `uint168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toUint168(uint256 value) internal pure returns (uint168) {
        if (value > type(uint168).max) {
            revert SafeCastOverflowedUintDowncast(168, value);
        }
        return uint168(value);
    }

    /**
     * @dev Returns the downcasted uint160 from uint256, reverting on
     * overflow (when the input is greater than largest uint160).
     *
     * Counterpart to Solidity's `uint160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toUint160(uint256 value) internal pure returns (uint160) {
        if (value > type(uint160).max) {
            revert SafeCastOverflowedUintDowncast(160, value);
        }
        return uint160(value);
    }

    /**
     * @dev Returns the downcasted uint152 from uint256, reverting on
     * overflow (when the input is greater than largest uint152).
     *
     * Counterpart to Solidity's `uint152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toUint152(uint256 value) internal pure returns (uint152) {
        if (value > type(uint152).max) {
            revert SafeCastOverflowedUintDowncast(152, value);
        }
        return uint152(value);
    }

    /**
     * @dev Returns the downcasted uint144 from uint256, reverting on
     * overflow (when the input is greater than largest uint144).
     *
     * Counterpart to Solidity's `uint144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toUint144(uint256 value) internal pure returns (uint144) {
        if (value > type(uint144).max) {
            revert SafeCastOverflowedUintDowncast(144, value);
        }
        return uint144(value);
    }

    /**
     * @dev Returns the downcasted uint136 from uint256, reverting on
     * overflow (when the input is greater than largest uint136).
     *
     * Counterpart to Solidity's `uint136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toUint136(uint256 value) internal pure returns (uint136) {
        if (value > type(uint136).max) {
            revert SafeCastOverflowedUintDowncast(136, value);
        }
        return uint136(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        if (value > type(uint128).max) {
            revert SafeCastOverflowedUintDowncast(128, value);
        }
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint120 from uint256, reverting on
     * overflow (when the input is greater than largest uint120).
     *
     * Counterpart to Solidity's `uint120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toUint120(uint256 value) internal pure returns (uint120) {
        if (value > type(uint120).max) {
            revert SafeCastOverflowedUintDowncast(120, value);
        }
        return uint120(value);
    }

    /**
     * @dev Returns the downcasted uint112 from uint256, reverting on
     * overflow (when the input is greater than largest uint112).
     *
     * Counterpart to Solidity's `uint112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toUint112(uint256 value) internal pure returns (uint112) {
        if (value > type(uint112).max) {
            revert SafeCastOverflowedUintDowncast(112, value);
        }
        return uint112(value);
    }

    /**
     * @dev Returns the downcasted uint104 from uint256, reverting on
     * overflow (when the input is greater than largest uint104).
     *
     * Counterpart to Solidity's `uint104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toUint104(uint256 value) internal pure returns (uint104) {
        if (value > type(uint104).max) {
            revert SafeCastOverflowedUintDowncast(104, value);
        }
        return uint104(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        if (value > type(uint96).max) {
            revert SafeCastOverflowedUintDowncast(96, value);
        }
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint88 from uint256, reverting on
     * overflow (when the input is greater than largest uint88).
     *
     * Counterpart to Solidity's `uint88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toUint88(uint256 value) internal pure returns (uint88) {
        if (value > type(uint88).max) {
            revert SafeCastOverflowedUintDowncast(88, value);
        }
        return uint88(value);
    }

    /**
     * @dev Returns the downcasted uint80 from uint256, reverting on
     * overflow (when the input is greater than largest uint80).
     *
     * Counterpart to Solidity's `uint80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toUint80(uint256 value) internal pure returns (uint80) {
        if (value > type(uint80).max) {
            revert SafeCastOverflowedUintDowncast(80, value);
        }
        return uint80(value);
    }

    /**
     * @dev Returns the downcasted uint72 from uint256, reverting on
     * overflow (when the input is greater than largest uint72).
     *
     * Counterpart to Solidity's `uint72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toUint72(uint256 value) internal pure returns (uint72) {
        if (value > type(uint72).max) {
            revert SafeCastOverflowedUintDowncast(72, value);
        }
        return uint72(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        if (value > type(uint64).max) {
            revert SafeCastOverflowedUintDowncast(64, value);
        }
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint56 from uint256, reverting on
     * overflow (when the input is greater than largest uint56).
     *
     * Counterpart to Solidity's `uint56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toUint56(uint256 value) internal pure returns (uint56) {
        if (value > type(uint56).max) {
            revert SafeCastOverflowedUintDowncast(56, value);
        }
        return uint56(value);
    }

    /**
     * @dev Returns the downcasted uint48 from uint256, reverting on
     * overflow (when the input is greater than largest uint48).
     *
     * Counterpart to Solidity's `uint48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toUint48(uint256 value) internal pure returns (uint48) {
        if (value > type(uint48).max) {
            revert SafeCastOverflowedUintDowncast(48, value);
        }
        return uint48(value);
    }

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        if (value > type(uint40).max) {
            revert SafeCastOverflowedUintDowncast(40, value);
        }
        return uint40(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        if (value > type(uint32).max) {
            revert SafeCastOverflowedUintDowncast(32, value);
        }
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint24 from uint256, reverting on
     * overflow (when the input is greater than largest uint24).
     *
     * Counterpart to Solidity's `uint24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toUint24(uint256 value) internal pure returns (uint24) {
        if (value > type(uint24).max) {
            revert SafeCastOverflowedUintDowncast(24, value);
        }
        return uint24(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        if (value > type(uint16).max) {
            revert SafeCastOverflowedUintDowncast(16, value);
        }
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        if (value > type(uint8).max) {
            revert SafeCastOverflowedUintDowncast(8, value);
        }
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        if (value < 0) {
            revert SafeCastOverflowedIntToUint(value);
        }
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int248 from int256, reverting on
     * overflow (when the input is less than smallest int248 or
     * greater than largest int248).
     *
     * Counterpart to Solidity's `int248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toInt248(int256 value) internal pure returns (int248 downcasted) {
        downcasted = int248(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(248, value);
        }
    }

    /**
     * @dev Returns the downcasted int240 from int256, reverting on
     * overflow (when the input is less than smallest int240 or
     * greater than largest int240).
     *
     * Counterpart to Solidity's `int240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toInt240(int256 value) internal pure returns (int240 downcasted) {
        downcasted = int240(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(240, value);
        }
    }

    /**
     * @dev Returns the downcasted int232 from int256, reverting on
     * overflow (when the input is less than smallest int232 or
     * greater than largest int232).
     *
     * Counterpart to Solidity's `int232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toInt232(int256 value) internal pure returns (int232 downcasted) {
        downcasted = int232(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(232, value);
        }
    }

    /**
     * @dev Returns the downcasted int224 from int256, reverting on
     * overflow (when the input is less than smallest int224 or
     * greater than largest int224).
     *
     * Counterpart to Solidity's `int224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toInt224(int256 value) internal pure returns (int224 downcasted) {
        downcasted = int224(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(224, value);
        }
    }

    /**
     * @dev Returns the downcasted int216 from int256, reverting on
     * overflow (when the input is less than smallest int216 or
     * greater than largest int216).
     *
     * Counterpart to Solidity's `int216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toInt216(int256 value) internal pure returns (int216 downcasted) {
        downcasted = int216(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(216, value);
        }
    }

    /**
     * @dev Returns the downcasted int208 from int256, reverting on
     * overflow (when the input is less than smallest int208 or
     * greater than largest int208).
     *
     * Counterpart to Solidity's `int208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toInt208(int256 value) internal pure returns (int208 downcasted) {
        downcasted = int208(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(208, value);
        }
    }

    /**
     * @dev Returns the downcasted int200 from int256, reverting on
     * overflow (when the input is less than smallest int200 or
     * greater than largest int200).
     *
     * Counterpart to Solidity's `int200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toInt200(int256 value) internal pure returns (int200 downcasted) {
        downcasted = int200(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(200, value);
        }
    }

    /**
     * @dev Returns the downcasted int192 from int256, reverting on
     * overflow (when the input is less than smallest int192 or
     * greater than largest int192).
     *
     * Counterpart to Solidity's `int192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toInt192(int256 value) internal pure returns (int192 downcasted) {
        downcasted = int192(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(192, value);
        }
    }

    /**
     * @dev Returns the downcasted int184 from int256, reverting on
     * overflow (when the input is less than smallest int184 or
     * greater than largest int184).
     *
     * Counterpart to Solidity's `int184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toInt184(int256 value) internal pure returns (int184 downcasted) {
        downcasted = int184(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(184, value);
        }
    }

    /**
     * @dev Returns the downcasted int176 from int256, reverting on
     * overflow (when the input is less than smallest int176 or
     * greater than largest int176).
     *
     * Counterpart to Solidity's `int176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toInt176(int256 value) internal pure returns (int176 downcasted) {
        downcasted = int176(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(176, value);
        }
    }

    /**
     * @dev Returns the downcasted int168 from int256, reverting on
     * overflow (when the input is less than smallest int168 or
     * greater than largest int168).
     *
     * Counterpart to Solidity's `int168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toInt168(int256 value) internal pure returns (int168 downcasted) {
        downcasted = int168(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(168, value);
        }
    }

    /**
     * @dev Returns the downcasted int160 from int256, reverting on
     * overflow (when the input is less than smallest int160 or
     * greater than largest int160).
     *
     * Counterpart to Solidity's `int160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toInt160(int256 value) internal pure returns (int160 downcasted) {
        downcasted = int160(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(160, value);
        }
    }

    /**
     * @dev Returns the downcasted int152 from int256, reverting on
     * overflow (when the input is less than smallest int152 or
     * greater than largest int152).
     *
     * Counterpart to Solidity's `int152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toInt152(int256 value) internal pure returns (int152 downcasted) {
        downcasted = int152(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(152, value);
        }
    }

    /**
     * @dev Returns the downcasted int144 from int256, reverting on
     * overflow (when the input is less than smallest int144 or
     * greater than largest int144).
     *
     * Counterpart to Solidity's `int144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toInt144(int256 value) internal pure returns (int144 downcasted) {
        downcasted = int144(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(144, value);
        }
    }

    /**
     * @dev Returns the downcasted int136 from int256, reverting on
     * overflow (when the input is less than smallest int136 or
     * greater than largest int136).
     *
     * Counterpart to Solidity's `int136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toInt136(int256 value) internal pure returns (int136 downcasted) {
        downcasted = int136(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(136, value);
        }
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toInt128(int256 value) internal pure returns (int128 downcasted) {
        downcasted = int128(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(128, value);
        }
    }

    /**
     * @dev Returns the downcasted int120 from int256, reverting on
     * overflow (when the input is less than smallest int120 or
     * greater than largest int120).
     *
     * Counterpart to Solidity's `int120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toInt120(int256 value) internal pure returns (int120 downcasted) {
        downcasted = int120(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(120, value);
        }
    }

    /**
     * @dev Returns the downcasted int112 from int256, reverting on
     * overflow (when the input is less than smallest int112 or
     * greater than largest int112).
     *
     * Counterpart to Solidity's `int112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toInt112(int256 value) internal pure returns (int112 downcasted) {
        downcasted = int112(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(112, value);
        }
    }

    /**
     * @dev Returns the downcasted int104 from int256, reverting on
     * overflow (when the input is less than smallest int104 or
     * greater than largest int104).
     *
     * Counterpart to Solidity's `int104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toInt104(int256 value) internal pure returns (int104 downcasted) {
        downcasted = int104(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(104, value);
        }
    }

    /**
     * @dev Returns the downcasted int96 from int256, reverting on
     * overflow (when the input is less than smallest int96 or
     * greater than largest int96).
     *
     * Counterpart to Solidity's `int96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toInt96(int256 value) internal pure returns (int96 downcasted) {
        downcasted = int96(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(96, value);
        }
    }

    /**
     * @dev Returns the downcasted int88 from int256, reverting on
     * overflow (when the input is less than smallest int88 or
     * greater than largest int88).
     *
     * Counterpart to Solidity's `int88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toInt88(int256 value) internal pure returns (int88 downcasted) {
        downcasted = int88(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(88, value);
        }
    }

    /**
     * @dev Returns the downcasted int80 from int256, reverting on
     * overflow (when the input is less than smallest int80 or
     * greater than largest int80).
     *
     * Counterpart to Solidity's `int80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toInt80(int256 value) internal pure returns (int80 downcasted) {
        downcasted = int80(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(80, value);
        }
    }

    /**
     * @dev Returns the downcasted int72 from int256, reverting on
     * overflow (when the input is less than smallest int72 or
     * greater than largest int72).
     *
     * Counterpart to Solidity's `int72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toInt72(int256 value) internal pure returns (int72 downcasted) {
        downcasted = int72(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(72, value);
        }
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toInt64(int256 value) internal pure returns (int64 downcasted) {
        downcasted = int64(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(64, value);
        }
    }

    /**
     * @dev Returns the downcasted int56 from int256, reverting on
     * overflow (when the input is less than smallest int56 or
     * greater than largest int56).
     *
     * Counterpart to Solidity's `int56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toInt56(int256 value) internal pure returns (int56 downcasted) {
        downcasted = int56(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(56, value);
        }
    }

    /**
     * @dev Returns the downcasted int48 from int256, reverting on
     * overflow (when the input is less than smallest int48 or
     * greater than largest int48).
     *
     * Counterpart to Solidity's `int48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toInt48(int256 value) internal pure returns (int48 downcasted) {
        downcasted = int48(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(48, value);
        }
    }

    /**
     * @dev Returns the downcasted int40 from int256, reverting on
     * overflow (when the input is less than smallest int40 or
     * greater than largest int40).
     *
     * Counterpart to Solidity's `int40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toInt40(int256 value) internal pure returns (int40 downcasted) {
        downcasted = int40(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(40, value);
        }
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toInt32(int256 value) internal pure returns (int32 downcasted) {
        downcasted = int32(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(32, value);
        }
    }

    /**
     * @dev Returns the downcasted int24 from int256, reverting on
     * overflow (when the input is less than smallest int24 or
     * greater than largest int24).
     *
     * Counterpart to Solidity's `int24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toInt24(int256 value) internal pure returns (int24 downcasted) {
        downcasted = int24(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(24, value);
        }
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toInt16(int256 value) internal pure returns (int16 downcasted) {
        downcasted = int16(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(16, value);
        }
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toInt8(int256 value) internal pure returns (int8 downcasted) {
        downcasted = int8(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(8, value);
        }
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        if (value > uint256(type(int256).max)) {
            revert SafeCastOverflowedUintToInt(value);
        }
        return int256(value);
    }

    /**
     * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
     */
    function toUint(bool b) internal pure returns (uint256 u) {
        assembly ("memory-safe") {
            u := iszero(iszero(b))
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Comparators.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides a set of functions to compare values.
 *
 * _Available since v5.1._
 */
library Comparators {
    function lt(uint256 a, uint256 b) internal pure returns (bool) {
        return a < b;
    }

    function gt(uint256 a, uint256 b) internal pure returns (bool) {
        return a > b;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/SlotDerivation.sol)
// This file was procedurally generated from scripts/generate/templates/SlotDerivation.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots
 * corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by
 * the solidity language / compiler.
 *
 * See https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays[Solidity docs for mappings and dynamic arrays.].
 *
 * Example usage:
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using StorageSlot for bytes32;
 *     using SlotDerivation for bytes32;
 *
 *     // Declare a namespace
 *     string private constant _NAMESPACE = "<namespace>"; // eg. OpenZeppelin.Slot
 *
 *     function setValueInNamespace(uint256 key, address newValue) internal {
 *         _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue;
 *     }
 *
 *     function getValueInNamespace(uint256 key) internal view returns (address) {
 *         return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value;
 *     }
 * }
 * ```
 *
 * TIP: Consider using this library along with {StorageSlot}.
 *
 * NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking
 * upgrade safety will ignore the slots accessed through this library.
 *
 * _Available since v5.1._
 */
library SlotDerivation {
    /**
     * @dev Derive an ERC-7201 slot from a string (namespace).
     */
    function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) {
        assembly ("memory-safe") {
            mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1))
            slot := and(keccak256(0x00, 0x20), not(0xff))
        }
    }

    /**
     * @dev Add an offset to a slot to get the n-th element of a structure or an array.
     */
    function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) {
        unchecked {
            return bytes32(uint256(slot) + pos);
        }
    }

    /**
     * @dev Derive the location of the first element in an array from the slot where the length is stored.
     */
    function deriveArray(bytes32 slot) internal pure returns (bytes32 result) {
        assembly ("memory-safe") {
            mstore(0x00, slot)
            result := keccak256(0x00, 0x20)
        }
    }

    /**
     * @dev Derive the location of a mapping element from the key.
     */
    function deriveMapping(bytes32 slot, address key) internal pure returns (bytes32 result) {
        assembly ("memory-safe") {
            mstore(0x00, and(key, shr(96, not(0))))
            mstore(0x20, slot)
            result := keccak256(0x00, 0x40)
        }
    }

    /**
     * @dev Derive the location of a mapping element from the key.
     */
    function deriveMapping(bytes32 slot, bool key) internal pure returns (bytes32 result) {
        assembly ("memory-safe") {
            mstore(0x00, iszero(iszero(key)))
            mstore(0x20, slot)
            result := keccak256(0x00, 0x40)
        }
    }

    /**
     * @dev Derive the location of a mapping element from the key.
     */
    function deriveMapping(bytes32 slot, bytes32 key) internal pure returns (bytes32 result) {
        assembly ("memory-safe") {
            mstore(0x00, key)
            mstore(0x20, slot)
            result := keccak256(0x00, 0x40)
        }
    }

    /**
     * @dev Derive the location of a mapping element from the key.
     */
    function deriveMapping(bytes32 slot, uint256 key) internal pure returns (bytes32 result) {
        assembly ("memory-safe") {
            mstore(0x00, key)
            mstore(0x20, slot)
            result := keccak256(0x00, 0x40)
        }
    }

    /**
     * @dev Derive the location of a mapping element from the key.
     */
    function deriveMapping(bytes32 slot, int256 key) internal pure returns (bytes32 result) {
        assembly ("memory-safe") {
            mstore(0x00, key)
            mstore(0x20, slot)
            result := keccak256(0x00, 0x40)
        }
    }

    /**
     * @dev Derive the location of a mapping element from the key.
     */
    function deriveMapping(bytes32 slot, string memory key) internal pure returns (bytes32 result) {
        assembly ("memory-safe") {
            let length := mload(key)
            let begin := add(key, 0x20)
            let end := add(begin, length)
            let cache := mload(end)
            mstore(end, slot)
            result := keccak256(begin, add(length, 0x20))
            mstore(end, cache)
        }
    }

    /**
     * @dev Derive the location of a mapping element from the key.
     */
    function deriveMapping(bytes32 slot, bytes memory key) internal pure returns (bytes32 result) {
        assembly ("memory-safe") {
            let length := mload(key)
            let begin := add(key, 0x20)
            let end := add(begin, length)
            let cache := mload(end)
            mstore(end, slot)
            result := keccak256(begin, add(length, 0x20))
            mstore(end, cache)
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC-1967 implementation slot:
 * ```solidity
 * contract ERC1967 {
 *     // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(newImplementation.code.length > 0);
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * TIP: Consider using this library along with {SlotDerivation}.
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    struct Int256Slot {
        int256 value;
    }

    struct StringSlot {
        string value;
    }

    struct BytesSlot {
        bytes value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Int256Slot` with member `value` located at `slot`.
     */
    function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `StringSlot` with member `value` located at `slot`.
     */
    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
     */
    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
        assembly ("memory-safe") {
            r.slot := store.slot
        }
    }

    /**
     * @dev Returns a `BytesSlot` with member `value` located at `slot`.
     */
    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
     */
    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
        assembly ("memory-safe") {
            r.slot := store.slot
        }
    }
}

Settings
{
  "remappings": [
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "poseidon-solidity/=lib/poseidon-solidity/contracts/",
    "zk-kit.solidity/=lib/zk-kit.solidity/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "@selfxyz/contracts/=lib/self/contracts/",
    "self/=lib/self/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "prague",
  "viaIR": false,
  "libraries": {
    "src/ManifestoCensus.sol": {
      "PoseidonT3": "0x90077cab41b84d4dd0bb311b1c820da0741d4726"
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"identityVerificationHubV2Address","type":"address"},{"internalType":"string","name":"scopeSeed","type":"string"},{"components":[{"internalType":"uint256","name":"olderThan","type":"uint256"},{"internalType":"string[]","name":"forbiddenCountries","type":"string[]"},{"internalType":"bool","name":"ofacEnabled","type":"bool"}],"internalType":"struct SelfUtils.UnformattedVerificationConfigV2","name":"unformattedVerificationConfig","type":"tuple"},{"internalType":"bytes32[]","name":"attestationAllowList","type":"bytes32[]"},{"internalType":"string","name":"requiredNationalityInput","type":"string"},{"components":[{"internalType":"string","name":"title","type":"string"},{"internalType":"string","name":"authors","type":"string"},{"internalType":"string","name":"date","type":"string"},{"internalType":"string","name":"manifestoText","type":"string"}],"internalType":"struct ManifestoCensus.ManifestoMetadata","name":"metadata","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyPledged","type":"error"},{"inputs":[],"name":"InvalidBufferSize","type":"error"},{"inputs":[],"name":"InvalidDataFormat","type":"error"},{"inputs":[],"name":"InvalidNationalityString","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"LeafAlreadyExists","type":"error"},{"inputs":[],"name":"LeafCannotBeZero","type":"error"},{"inputs":[],"name":"LeafGreaterThanSnarkScalarField","type":"error"},{"inputs":[{"internalType":"bytes3","name":"required","type":"bytes3"},{"internalType":"bytes3","name":"provided","type":"bytes3"}],"name":"NationalityMismatch","type":"error"},{"inputs":[],"name":"NoAttestationTypesProvided","type":"error"},{"inputs":[],"name":"NullifierAlreadyUsed","type":"error"},{"inputs":[],"name":"SelfVerificationOnly","type":"error"},{"inputs":[],"name":"UnauthorizedCaller","type":"error"},{"inputs":[{"internalType":"bytes32","name":"attestationId","type":"bytes32"}],"name":"UnsupportedAttestation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"newRoot","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"CensusRootUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"signer","type":"address"},{"indexed":false,"internalType":"uint256","name":"nullifier","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"attestationId","type":"bytes32"}],"name":"IdentityVerified","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"signer","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"Pledged","type":"event"},{"inputs":[],"name":"AUTHORS","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DATE","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANIFESTO","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TITLE","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"allowedAttestation","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"computeLeaf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getAllowedAttestationIds","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCensusRoot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"getConfigId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"root","type":"uint256"}],"name":"getRootBlockNumber","outputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVerificationParameters","outputs":[{"internalType":"uint256","name":"minAge","type":"uint256"},{"internalType":"bool","name":"minAgeEnabled","type":"bool"},{"internalType":"bool","name":"ofacEnabled","type":"bool"},{"internalType":"string[]","name":"forbiddenCountries","type":"string[]"},{"internalType":"bytes3","name":"nationality","type":"bytes3"},{"internalType":"bytes32[]","name":"attestationTypes","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"hasPledged","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"identityVerificationHub","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"attestationId","type":"bytes32"}],"name":"isAttestationAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"nullifierUsed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"output","type":"bytes"},{"internalType":"bytes","name":"userData","type":"bytes"}],"name":"onVerificationSuccess","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pledge","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"pledgeCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"pledgeTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"},{"internalType":"uint256","name":"cutoff","type":"uint256"}],"name":"pledgedBefore","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"requiredNationality","outputs":[{"internalType":"bytes3","name":"","type":"bytes3"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"scope","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"scopeLabel","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"verificationConfig","outputs":[{"internalType":"bool","name":"olderThanEnabled","type":"bool"},{"internalType":"uint256","name":"olderThan","type":"uint256"},{"internalType":"bool","name":"forbiddenCountriesEnabled","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"verificationConfigId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"proofPayload","type":"bytes"},{"internalType":"bytes","name":"userContextData","type":"bytes"}],"name":"verifySelfProof","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a060405234801561000f575f5ffd5b50604051612f73380380612f7383398101604081905261002e91611050565b6001600160a01b038616608052858561004f308261004a6102d6565b610329565b5f81905550505082515f03610077576040516302ad59c160e21b815260040160405180910390fd5b610083600b60646103e0565b601b61008f86826111ca565b5061009984610413565b8051600e805491151560ff199283161781556020830151600f55604083015160108054911515919093161790915560608201516100da906011906004610bbe565b5060808201516100f09060078301906003610bfc565b50506040516309ddb09160e01b81526001600160a01b03881691506309ddb0919061012090600e90600401611284565b6020604051808303815f875af115801561013c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610160919061130b565b6016555f5b83518110156101e3575f84828151811061018157610181611322565b6020908102919091018101515f818152601890925260408220805460ff1916600190811790915560198054808301825593527f944998273e477b495144fb8794c914197f3ccb46be2900f4698fd0ef743c969590920155919091019050610165565b5060208401515115610249575f5b84602001515181101561024757601a8560200151828151811061021657610216611322565b60209081029190910181015182546001810184555f93845291909220019061023e90826111ca565b506001016101f1565b505b81515f0361026257601c805462ffffff19169055610282565b61026b82610485565b601c805462ffffff191660e89290921c9190911790555b805160019061029190826111ca565b5060208101516002906102a490826111ca565b5060408101516003906102b790826111ca565b5060608101516004906102ca90826111ca565b5050505050505061143a565b5f4661a4ec8190036102fd5773f134707a4c4a3a76b8410fc0294d620a7c34158191505090565b8062aa044c0361032257730a782f7f9f8aac6e0bacaf3cd4aa292c3275c6f291505090565b5f91505090565b5f6001600160a01b03821661033f57505f6103d9565b5f61034a858461058f565b90505f6103568561064e565b604080518082018252848152602081018390529051632b0aac7f60e11b81529192506001600160a01b0386169163561558fe9161039591600401611336565b602060405180830381865afa1580156103b0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103d4919061130b565b925050505b9392505050565b805f0361040057604051630c01a34b60e41b815260040160405180910390fd5b5f825561040f60018301829055565b5050565b61041b610c86565b610423610cc1565b6040838101805115158352805115156020808501919091529051151583830152815160a0810183528551151581528551818301529085018051511515928201929092529051606082019061047690610764565b81526020019190915292915050565b80515f9082906003146104ab5760405163ceb73e5760e01b815260040160405180910390fd5b6040805160038082528183019092525f916020820181803683370190505090505f5b6003811015610583575f8382815181106104e9576104e9611322565b016020015160f81c9050606181108015906105085750607a8160ff1611155b1561051b5761051860208261137a565b90505b60418160ff1610806105305750605a8160ff16115b1561054e5760405163ceb73e5760e01b815260040160405180910390fd5b8060f81b83838151811061056457610564611322565b60200101906001600160f81b03191690815f1a905350506001016104cd565b50602001519392505050565b5f8061059a84610924565b90505f6105b16105ac8383601f610afe565b61064e565b90505f6105c46105ac84601f602a610afe565b604080518082018252848152602081018390529051632b0aac7f60e11b81529192506001600160a01b0387169163561558fe9161060391600401611336565b602060405180830381865afa15801561061e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610642919061130b565b93505050505b92915050565b5f5f829050601f815111156106b85760405162461bcd60e51b815260206004820152602560248201527f537472696e6720746f6f206c6f6e6720666f7220426967496e7420636f6e76656044820152643939b4b7b760d91b60648201526084015b60405180910390fd5b5f805b825181101561075c57607f8382815181106106d8576106d8611322565b016020015160f81c111561072e5760405162461bcd60e51b815260206004820152601c60248201527f4e6f6e2d4153434949206368617261637465722064657465637465640000000060448201526064016106af565b82818151811061074057610740611322565b60209101015160f81c60089290921b91909117906001016106bb565b509392505050565b61076c610cdf565b601f600460605f5b855181101561083f575f86828151811061079057610790611322565b6020026020010151905080516003146108115760405162461bcd60e51b815260206004820152603760248201527f496e76616c696420636f756e74727920636f64653a206d75737420626520657860448201527f6163746c7920332063686172616374657273206c6f6e6700000000000000000060648201526084016106af565b82816040516020016108249291906113aa565b60408051601f19818403018152919052925050600101610774565b508051835f81600161085182866113c6565b61085b91906113d9565b61086591906113ec565b90505f5b818110801561087757508581105b15610918575f805b848110156108ec575f81610893858861140b565b61089d91906113c6565b9050868110156108e3575f8882815181106108ba576108ba611322565b016020015160f81c90505f6108d084600861140b565b90506108de82821b866113c6565b945050505b5060010161087f565b508089836004811061090057610900611322565b6020020152508061091081611422565b915050610869565b50505050505050919050565b604080518082018252601081526f181899199a1a9b1b9c1cb0b131b232b360811b60208201528151602a80825260608281019094526001600160a01b03851692915f91602082018180368337019050509050600360fc1b815f8151811061098d5761098d611322565b60200101906001600160f81b03191690815f1a905350600f60fb1b816001815181106109bb576109bb611322565b60200101906001600160f81b03191690815f1a9053505f5b6014811015610af557826004856109eb84600c6113c6565b602081106109fb576109fb611322565b1a60f81b6001600160f81b031916901c60f81c60ff1681518110610a2157610a21611322565b01602001516001600160f81b03191682610a3c83600261140b565b610a479060026113c6565b81518110610a5757610a57611322565b60200101906001600160f81b03191690815f1a9053508284610a7a83600c6113c6565b60208110610a8a57610a8a611322565b825191901a600f16908110610aa157610aa1611322565b01602001516001600160f81b03191682610abc83600261140b565b610ac79060036113c6565b81518110610ad757610ad7611322565b60200101906001600160f81b03191690815f1a9053506001016109d3565b50949350505050565b6060835f610b0c85856113d9565b6001600160401b03811115610b2357610b23610d2c565b6040519080825280601f01601f191660200182016040528015610b4d576020820181803683370190505b509050845b84811015610bb457828181518110610b6c57610b6c611322565b01602001516001600160f81b03191682610b8688846113d9565b81518110610b9657610b96611322565b60200101906001600160f81b03191690815f1a905350600101610b52565b5095945050505050565b8260048101928215610bec579160200282015b82811115610bec578251825591602001919060010190610bd1565b50610bf8929150610cfd565b5090565b600183019183908215610bec579160200282015f5b83821115610c4d57835183826101000a81548160ff02191690831515021790555092602001926001016020815f01049283019260010302610c11565b8015610c795782816101000a81549060ff02191690556001016020815f01049283019260010302610c4d565b5050610bf8929150610cfd565b6040518060a001604052805f151581526020015f81526020015f15158152602001610caf610cdf565b8152602001610cbc610cc1565b905290565b60405180606001604052806003906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b5b80821115610bf8575f8155600101610cfe565b80516001600160a01b0381168114610d27575f5ffd5b919050565b634e487b7160e01b5f52604160045260245ffd5b604051606081016001600160401b0381118282101715610d6257610d62610d2c565b60405290565b604051608081016001600160401b0381118282101715610d6257610d62610d2c565b604051601f8201601f191681016001600160401b0381118282101715610db257610db2610d2c565b604052919050565b5f82601f830112610dc9575f5ffd5b81516001600160401b03811115610de257610de2610d2c565b610df5601f8201601f1916602001610d8a565b818152846020838601011115610e09575f5ffd5b8160208501602083015e5f918101602001919091529392505050565b5f6001600160401b03821115610e3d57610e3d610d2c565b5060051b60200190565b80518015158114610d27575f5ffd5b5f60608284031215610e66575f5ffd5b610e6e610d40565b8251815260208301519091506001600160401b03811115610e8d575f5ffd5b8201601f81018413610e9d575f5ffd5b8051610eb0610eab82610e25565b610d8a565b8082825260208201915060208360051b850101925086831115610ed1575f5ffd5b602084015b83811015610f115780516001600160401b03811115610ef3575f5ffd5b610f0289602083890101610dba565b84525060209283019201610ed6565b50602085015250610f2791505060408301610e47565b604082015292915050565b5f82601f830112610f41575f5ffd5b8151610f4f610eab82610e25565b8082825260208201915060208360051b860101925085831115610f70575f5ffd5b602085015b83811015610bb4578051835260209283019201610f75565b5f60808284031215610f9d575f5ffd5b610fa5610d68565b82519091506001600160401b03811115610fbd575f5ffd5b610fc984828501610dba565b82525060208201516001600160401b03811115610fe4575f5ffd5b610ff084828501610dba565b60208301525060408201516001600160401b0381111561100e575f5ffd5b61101a84828501610dba565b60408301525060608201516001600160401b03811115611038575f5ffd5b61104484828501610dba565b60608301525092915050565b5f5f5f5f5f5f60c08789031215611065575f5ffd5b61106e87610d11565b60208801519096506001600160401b03811115611089575f5ffd5b61109589828a01610dba565b604089015190965090506001600160401b038111156110b2575f5ffd5b6110be89828a01610e56565b606089015190955090506001600160401b038111156110db575f5ffd5b6110e789828a01610f32565b608089015190945090506001600160401b03811115611104575f5ffd5b61111089828a01610dba565b60a089015190935090506001600160401b0381111561112d575f5ffd5b61113989828a01610f8d565b9150509295509295509295565b600181811c9082168061115a57607f821691505b60208210810361117857634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156111c557805f5260205f20601f840160051c810160208510156111a35750805b601f840160051c820191505b818110156111c2575f81556001016111af565b50505b505050565b81516001600160401b038111156111e3576111e3610d2c565b6111f7816111f18454611146565b8461117e565b6020601f821160018114611229575f83156112125750848201515b5f19600385901b1c1916600184901b1784556111c2565b5f84815260208120601f198516915b828110156112585787850151825560209485019460019092019101611238565b508482101561127557868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b815460ff908116151582526001830154602083015260028301541615156040820152610140810160608201600384015f5b60048110156112d45781548352602090920191600191820191016112b5565b505050600783015460ff808216151560e0850152600882901c8116151561010085015260109190911c161515610120830152610648565b5f6020828403121561131b575f5ffd5b5051919050565b634e487b7160e01b5f52603260045260245ffd5b6040810181835f5b600281101561135d57815183526020928301929091019060010161133e565b50505092915050565b634e487b7160e01b5f52601160045260245ffd5b60ff828116828216039081111561064857610648611366565b5f81518060208401855e5f93019283525090919050565b5f6113be6113b88386611393565b84611393565b949350505050565b8082018082111561064857610648611366565b8181038181111561064857610648611366565b5f8261140657634e487b7160e01b5f52601260045260245ffd5b500490565b808202811582820484141761064857610648611366565b5f6001820161143357611433611366565b5060010190565b608051611b136114605f395f81816104000152818161078101526109c90152611b135ff3fe608060405234801561000f575f5ffd5b5060043610610187575f3560e01c80639b352380116100d9578063c1da869111610093578063d161802b1161006e578063d161802b146103d0578063e4861bdd146103e3578063e5638891146103eb578063ebae66f0146103f3575f5ffd5b8063c1da86911461038b578063c6d6c183146103a1578063cda363b0146103aa575f5ffd5b80639b35238014610332578063ab269a2b14610345578063ada1b3191461034d578063b73cc09814610365578063ba3ec7411461037a578063bb44374414610382575f5ffd5b80636e62d0a8116101445780637b6c7c711161011f5780637b6c7c71146102dd5780637ef838041461030057806388ffe867146103155780638d2d8d6a1461031f575f5ffd5b80636e62d0a814610292578063747bfb611461029957806379f95ee9146102bb575f5ffd5b8063037b410e1461018b5780630a8f0b3e146101c7578063129a0c00146101f4578063231841e11461020e5780632b7a8feb14610240578063650e5fcf1461026a575b5f5ffd5b600e54600f546010546101a39260ff90811692911683565b60408051931515845260208401929092521515908201526060015b60405180910390f35b6101e66101d536600461110c565b60056020525f908152604090205481565b6040519081526020016101be565b6101fc61042a565b6040516101be96959493929190611194565b61023061021c366004611234565b5f9081526018602052604090205460ff1690565b60405190151581526020016101be565b61023061024e36600461110c565b6001600160a01b03165f90815260056020526040902054151590565b6101e6610278366004611234565b5f908152600d60205260409020546001600160401b031690565b5f546101e6565b6102306102a7366004611234565b60186020525f908152604090205460ff1681565b6102306102c9366004611234565b60176020525f908152604090205460ff1681565b6101e66102eb36600461110c565b60581b600160581b600160f81b031660011790565b6103086106d1565b6040516101be919061124b565b61031d61075d565b005b61031d61032d366004611342565b610776565b6102306103403660046113a5565b6107e5565b610308610816565b6101e661035b3660046113cd565b6016549392505050565b61036d610823565b6040516101be9190611418565b6103086108c1565b6101e660165481565b6008545f908152600960205260409020546101e6565b6101e660065481565b601c546103b79060e81b81565b6040516001600160e81b031990911681526020016101be565b61031d6103de36600461146e565b6108ce565b610308610a71565b610308610a7e565b6040516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681526020016101be565b6040805160a081018252600e805460ff90811615158352600f546020840152601054161515828401528251608081019093525f928392839260609284928492849282850190601160048282826020028201915b81548152602001906001019080831161047d575050509183525050604080516060810191829052602090920191906007840190600390825f855b825461010083900a900460ff1615158152602060019283018181049485019490930390920291018084116104b757505050929093525050505060208101518151608083015151601c54601a54939b50919950975060e81b94509091506001600160401b0381111561052a5761052a61125d565b60405190808252806020026020018201604052801561055d57816020015b60608152602001906001900390816105485790505b5093505f5b601a5481101561063357601a818154811061057f5761057f6114d8565b905f5260205f20018054610592906114ec565b80601f01602080910402602001604051908101604052809291908181526020018280546105be906114ec565b80156106095780601f106105e057610100808354040283529160200191610609565b820191905f5260205f20905b8154815290600101906020018083116105ec57829003601f168201915b5050505050858281518110610620576106206114d8565b6020908102919091010152600101610562565b506019546001600160401b0381111561064e5761064e61125d565b604051908082528060200260200182016040528015610677578160200160208202803683370190505b5091505f5b6019548110156106c75760198181548110610699576106996114d8565b905f5260205f2001548382815181106106b4576106b46114d8565b602090810291909101015260010161067c565b5050909192939495565b600180546106de906114ec565b80601f016020809104026020016040519081016040528092919081815260200182805461070a906114ec565b80156107555780601f1061072c57610100808354040283529160200191610755565b820191905f5260205f20905b81548152906001019060200180831161073857829003601f168201915b505050505081565b6040516315af233b60e31b815260040160405180910390fd5b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146107bf57604051635c427cd960e01b815260040160405180910390fd5b5f828060200190518101906107d491906116ad565b90506107e08183610a8b565b505050565b6001600160a01b0382165f90815260056020526040812054801580159061080c5750828111155b9150505b92915050565b601b80546106de906114ec565b6019546060905f906001600160401b038111156108425761084261125d565b60405190808252806020026020018201604052801561086b578160200160208202803683370190505b5090505f5b6019548110156108bb576019818154811061088d5761088d6114d8565b905f5260205f2001548282815181106108a8576108a86114d8565b6020908102919091010152600101610870565b50919050565b600280546106de906114ec565b60208310156108f05760405163a512e2ff60e01b815260040160405180910390fd5b60408110156109125760405163a512e2ff60e01b815260040160405180910390fd5b83355f610922602082858761186d565b61092b91611894565b90505f61093c60406020868861186d565b61094591611894565b90505f610955856040818961186d565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920182905250601654949550939250610995915050565b90505f60025f60081b5f548c8c6040516020016109b69594939291906118b1565b60405160208183030381529060405290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f7e83aee82848b8b604051602001610a0c939291906118eb565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610a38929190611904565b5f604051808303815f87803b158015610a4f575f5ffd5b505af1158015610a61573d5f5f3e3d5ffd5b5050505050505050505050505050565b600380546106de906114ec565b600480546106de906114ec565b81515f9081526018602052604090205460ff16610ac657815160405163d4547dd560e01b815260048101919091526024015b60405180910390fd5b6040808301515f8181526017602052919091205460ff1615610afb57604051636569570160e11b815260040160405180910390fd5b60208301516001600160a01b038116610b2757604051632057875960e21b815260040160405180910390fd5b601c5460e81b6001600160e81b03191615610b9f575f610b4a8560e00151610d3b565b601c5490915060e81b6001600160e81b031990811690821614610b9d57601c54604051631c40172160e31b81526001600160e81b031960e89290921b821660048201529082166024820152604401610abd565b505b6001600160a01b0381165f9081526005602052604090205415610bd55760405163b0ca2ff560e01b815260040160405180910390fd5b5f828152601760209081526040808320805460ff191660011790556001600160a01b0384168352600590915281204290556006805491610c1483611945565b90915550506001600160581b600160f81b03605883901b16177f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018110610c915760405162461bcd60e51b8152602060048201526012602482015271496e76616c6964206c6561662076616c756560701b6044820152606401610abd565b610c9c600782610e45565b50610ca5611017565b84516040516001600160a01b038416917f52dcbba5720a8ca5da4e0eed87dfd81e6d1fe4726470a0037a8aba140197959691610ce991878252602082015260400190565b60405180910390a2816001600160a01b03167f2726ce6e3b7987cbbb10c5a55b44725526c540fbba590cfc20afab691fa45edf42604051610d2c91815260200190565b60405180910390a25050505050565b80515f908290600314610d615760405163ceb73e5760e01b815260040160405180910390fd5b6040805160038082528183019092525f916020820181803683370190505090505f5b6003811015610e39575f838281518110610d9f57610d9f6114d8565b016020015160f81c905060618110801590610dbe5750607a8160ff1611155b15610dd157610dce60208261195d565b90505b60418160ff161080610de65750605a8160ff16115b15610e045760405163ceb73e5760e01b815260040160405180910390fd5b8060f81b838381518110610e1a57610e1a6114d8565b60200101906001600160f81b03191690815f1a90535050600101610d83565b50602001519392505050565b5f7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018210610e86576040516361c0541760e11b815260040160405180910390fd5b815f03610ea6576040516314b48df160e11b815260040160405180910390fd5b5f82815260038401602052604090205415610ed4576040516312c50cad60e11b815260040160405180910390fd5b825460018085015490610ee8908390611976565b610ef3826002611a6c565b1015610f0557610f0281611945565b90505b60018501819055835f5b82811015610fdd578084901c600116600103610fc2576040805180820182525f83815260028a0160209081529083902054825281018490529051632b0aac7f60e11b81527390077cab41b84d4dd0bb311b1c820da0741d47269163561558fe91610f7c9190600401611a77565b602060405180830381865af4158015610f97573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fbb9190611aa7565b9150610fd5565b5f81815260028801602052604090208290555b600101610f0f565b50610fe783611945565b8087555f928352600287016020908152604080852084905596845260039097019096529390209390935550919050565b6008545f9081526009602052604090205480611034600b8261109a565b5f818152600d6020908152604091829020805467ffffffffffffffff1916436001600160401b03811691909117909155915191825283917fac84e1f746682c16ccc7cac6060f24ba0d81b110e6dc4cfa95bbfae24a5fc07d910160405180910390a25050565b81545f9083826110a983611945565b9091555060018401805491925083906110cb906110c68486611abe565b6110d2565b5550505050565b5f8261080c6110ee846110ea845f9081526020902090565b0190565b90565b80356001600160a01b0381168114611107575f5ffd5b919050565b5f6020828403121561111c575f5ffd5b611125826110f1565b9392505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b5f8151808452602084019350602083015f5b8281101561118a57815186526020958601959091019060010161116c565b5093949350505050565b5f60c082018883528715156020840152861515604084015260c0606084015280865180835260e08501915060e08160051b8601019250602088015f5b828110156112015760df198786030184526111ec85835161112c565b945060209384019391909101906001016111d0565b5050506001600160e81b0319861660808501525082810360a0840152611227818561115a565b9998505050505050505050565b5f60208284031215611244575f5ffd5b5035919050565b602081525f611125602083018461112c565b634e487b7160e01b5f52604160045260245ffd5b6040516101a081016001600160401b03811182821017156112945761129461125d565b60405290565b604051601f8201601f191681016001600160401b03811182821017156112c2576112c261125d565b604052919050565b5f6001600160401b038211156112e2576112e261125d565b50601f01601f191660200190565b5f82601f8301126112ff575f5ffd5b813561131261130d826112ca565b61129a565b818152846020838601011115611326575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f5f60408385031215611353575f5ffd5b82356001600160401b03811115611368575f5ffd5b611374858286016112f0565b92505060208301356001600160401b0381111561138f575f5ffd5b61139b858286016112f0565b9150509250929050565b5f5f604083850312156113b6575f5ffd5b6113bf836110f1565b946020939093013593505050565b5f5f5f606084860312156113df575f5ffd5b833592506020840135915060408401356001600160401b03811115611402575f5ffd5b61140e868287016112f0565b9150509250925092565b602081525f611125602083018461115a565b5f5f83601f84011261143a575f5ffd5b5081356001600160401b03811115611450575f5ffd5b602083019150836020828501011115611467575f5ffd5b9250929050565b5f5f5f5f60408587031215611481575f5ffd5b84356001600160401b03811115611496575f5ffd5b6114a28782880161142a565b90955093505060208501356001600160401b038111156114c0575f5ffd5b6114cc8782880161142a565b95989497509550505050565b634e487b7160e01b5f52603260045260245ffd5b600181811c9082168061150057607f821691505b6020821081036108bb57634e487b7160e01b5f52602260045260245ffd5b5f82601f83011261152d575f5ffd5b611537608061129a565b806080840185811115611548575f5ffd5b845b8181101561156257805184526020938401930161154a565b509095945050505050565b5f82601f83011261157c575f5ffd5b815161158a61130d826112ca565b81815284602083860101111561159e575f5ffd5b8160208501602083015e5f918101602001919091529392505050565b5f82601f8301126115c9575f5ffd5b81516001600160401b038111156115e2576115e261125d565b8060051b6115f26020820161129a565b9182526020818501810192908101908684111561160d575f5ffd5b6020860192505b838310156116525782516001600160401b03811115611631575f5ffd5b611640886020838a010161156d565b83525060209283019290910190611614565b9695505050505050565b5f82601f83011261166b575f5ffd5b611675606061129a565b806060840185811115611686575f5ffd5b845b81811015611562578051801515811461169f575f5ffd5b845260209384019301611688565b5f602082840312156116bd575f5ffd5b81516001600160401b038111156116d2575f5ffd5b820161024081850312156116e4575f5ffd5b6116ec611271565b815181526020808301519082015260408083015190820152611711856060840161151e565b606082015260e08201516001600160401b0381111561172e575f5ffd5b61173a8682850161156d565b6080830152506101008201516001600160401b03811115611759575f5ffd5b611765868285016115ba565b60a0830152506101208201516001600160401b03811115611784575f5ffd5b6117908682850161156d565b60c0830152506101408201516001600160401b038111156117af575f5ffd5b6117bb8682850161156d565b60e0830152506101608201516001600160401b038111156117da575f5ffd5b6117e68682850161156d565b610100830152506101808201516001600160401b03811115611806575f5ffd5b6118128682850161156d565b610120830152506101a08201516001600160401b03811115611832575f5ffd5b61183e8682850161156d565b610140830152506101c082015161016082015261185f856101e0840161165c565b610180820152949350505050565b5f5f8585111561187b575f5ffd5b83861115611887575f5ffd5b5050820193919092039150565b80356020831015610810575f19602084900360031b1b1692915050565b60f886901b6001600160f81b031916815260ff198516600182015260208101849052818360408301375f9101604001908152949350505050565b838152818360208301375f910160200190815292915050565b604081525f611916604083018561112c565b8281036020840152611928818561112c565b95945050505050565b634e487b7160e01b5f52601160045260245ffd5b5f6001820161195657611956611931565b5060010190565b60ff828116828216039081111561081057610810611931565b8082018082111561081057610810611931565b6001815b60018411156119c4578085048111156119a8576119a8611931565b60018416156119b657908102905b60019390931c92800261198d565b935093915050565b5f826119da57506001610810565b816119e657505f610810565b81600181146119fc5760028114611a0657611a22565b6001915050610810565b60ff841115611a1757611a17611931565b50506001821b610810565b5060208310610133831016604e8410600b8410161715611a45575081810a610810565b611a515f198484611989565b805f1904821115611a6457611a64611931565b029392505050565b5f61112583836119cc565b6040810181835f5b6002811015611a9e578151835260209283019290910190600101611a7f565b50505092915050565b5f60208284031215611ab7575f5ffd5b5051919050565b5f82611ad857634e487b7160e01b5f52601260045260245ffd5b50069056fea2646970667358221220a251cdb6128c837b3e67a0462fe7a77714364cf72afd6c00522e8e2f7825463b64736f6c634300081c0033000000000000000000000000e57f4773bd9c9d8b6cd70431117d353298b9f5bf00000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000176d616e69666573746f2d636c65616e2d7374726565747300000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000031436f6c6c6563746976652046726565646f6d3a2041204d616e69666573746f20666f722050617274696369706174696f6e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016444156494e43492e766f746520436f6d6d756e69747900000000000000000000000000000000000000000000000000000000000000000000000000000000000a323032352d31312d31360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006d52320436f6c6c6563746976652046726565646f6d3a2041204d616e69666573746f20666f722050617274696369706174696f6e0a0a576520776572652070726f6d697365642064656d6f63726163792e0a5768617420776520676f7420776173207065726d697373696f6e2e0a5065726d697373696f6e20746f2063686f6f7365206265747765656e206f7074696f6e73207765206469646e2774206372656174652e0a5065726d697373696f6e20746f20737065616b206f6e6c79207768656e2073706f6b656e20746f2e0a0a5065726d697373696f6e20746f20657869737420696e736964652073797374656d73206275696c7420746f20636f6e7461696e2075732e0a5468657920746f6c642075732074686973207761732066726565646f6d2e0a4275742066726565646f6d20776974686f7574206167656e637920697320746865617465722e0a5765207363726f6c6c2e20576520766f74652e205765207369676e207065746974696f6e732e0a416e64207374696c6c2c2074686520776f726c64206275726e732c20696e657175616c6974792067726f77732c20616e6420747275737420636f6c6c61707365732e0a54686520746872656164732074686174206f6e63652068656c6420757320746f676574686572206172652074656172696e672061706172742e0a2a2a456e6f7567682e2a2a0a0a57652072656675736520746f207369742071756965746c79207768696c65206f746865727320646563696465206f7572206675747572652e0a57652072656675736520746f206d697374616b6520726570726573656e746174696f6e20666f722070617274696369706174696f6e2e0a5468652073797374656d732074686174206661696c656420757320617265206e6f7420746865206f6e6c79206f6e6573207765206861766520746f206c6976652062792e0a46726565646f6d20626567696e7320776974682070617274696369706174696f6e2c206e6f74206f62656469656e63652e0a0a45766572792068756d616e206465736572766573206120766f69636520696e207468652073797374656d73207468657920646570656e64206f6e2c0a74686520706c6174666f726d732074686579207573652c2074686520706f6c69636965732074686174207368617065207468656d2c0a746865206675747572652074686579276c6c20696e68657269742e0a0a2a2a57652062656c696576652070726976616379206973206e6f74206120666561747572652c2069742773206120666f756e646174696f6e2e2a2a0a54686520726967687420746f2065786973742c207468696e6b2c20616e6420636f6e6e65637420776974686f7574207375727665696c6c616e63652e0a50726976616379206973207468652073706163652077686572652064697373656e742c20637265617469766974792c20616e642064656d6f63726163792061726520626f726e2e0a0a2a2a57652062656c6965766520617574686f72697479206d757374206265206163636f756e7461626c652c20616e6420706f776572207472616e73706172656e742e2a2a0a476f7665726e616e6365206973206e6f7420736f6d657468696e6720646f6e6520746f2075733b206974277320736f6d657468696e6720776520646f2c20746f6765746865722e0a0a2a2a57652062656c6965766520746563686e6f6c6f6779206973206120746f6f6c2c206e6f742061206d61737465722e2a2a0a4c696b65206c616e67756167652c206974206d7573742062656c6f6e6720746f2065766572796f6e652c0a61207075626c696320676f6f6420746f206275696c642074727573742c206e6f7420657874726163742069742e0a0a57652062656c6965766520696e2073656c662d736f7665726569676e20696e6672617374727563747572652c0a7472616e73706172656e63792061732074727574682c0a616e6420636f6c6c61626f726174696f6e20617320737472656e6774682e0a0a23202a2a57652061726520746865206275696c64657273206f662074686520636f6d6d6f6e732e2a2a0a5468652070656f706c652077686f2072656675736520746f2072656d61696e206f6e2074686520736964656c696e65732e0a54686520647265616d6572732077686f207475726e206672757374726174696f6e20696e746f20696e76656e74696f6e2e0a54686520636f6d6d756e69746965732077686f207475726e20696465617320696e746f20616374696f6e2e0a0a2a2a426563617573652074686520667574757265207765206c69766520696e20646570656e6473206f6e2074686520676f7665726e616e6365207765206163686965766520746f6461792e2a2a0a2a2a23436f6c6c65637469766546726565646f6d2a2a0a0000000000000000000000

Deployed Bytecode

0x608060405234801561000f575f5ffd5b5060043610610187575f3560e01c80639b352380116100d9578063c1da869111610093578063d161802b1161006e578063d161802b146103d0578063e4861bdd146103e3578063e5638891146103eb578063ebae66f0146103f3575f5ffd5b8063c1da86911461038b578063c6d6c183146103a1578063cda363b0146103aa575f5ffd5b80639b35238014610332578063ab269a2b14610345578063ada1b3191461034d578063b73cc09814610365578063ba3ec7411461037a578063bb44374414610382575f5ffd5b80636e62d0a8116101445780637b6c7c711161011f5780637b6c7c71146102dd5780637ef838041461030057806388ffe867146103155780638d2d8d6a1461031f575f5ffd5b80636e62d0a814610292578063747bfb611461029957806379f95ee9146102bb575f5ffd5b8063037b410e1461018b5780630a8f0b3e146101c7578063129a0c00146101f4578063231841e11461020e5780632b7a8feb14610240578063650e5fcf1461026a575b5f5ffd5b600e54600f546010546101a39260ff90811692911683565b60408051931515845260208401929092521515908201526060015b60405180910390f35b6101e66101d536600461110c565b60056020525f908152604090205481565b6040519081526020016101be565b6101fc61042a565b6040516101be96959493929190611194565b61023061021c366004611234565b5f9081526018602052604090205460ff1690565b60405190151581526020016101be565b61023061024e36600461110c565b6001600160a01b03165f90815260056020526040902054151590565b6101e6610278366004611234565b5f908152600d60205260409020546001600160401b031690565b5f546101e6565b6102306102a7366004611234565b60186020525f908152604090205460ff1681565b6102306102c9366004611234565b60176020525f908152604090205460ff1681565b6101e66102eb36600461110c565b60581b600160581b600160f81b031660011790565b6103086106d1565b6040516101be919061124b565b61031d61075d565b005b61031d61032d366004611342565b610776565b6102306103403660046113a5565b6107e5565b610308610816565b6101e661035b3660046113cd565b6016549392505050565b61036d610823565b6040516101be9190611418565b6103086108c1565b6101e660165481565b6008545f908152600960205260409020546101e6565b6101e660065481565b601c546103b79060e81b81565b6040516001600160e81b031990911681526020016101be565b61031d6103de36600461146e565b6108ce565b610308610a71565b610308610a7e565b6040516001600160a01b037f000000000000000000000000e57f4773bd9c9d8b6cd70431117d353298b9f5bf1681526020016101be565b6040805160a081018252600e805460ff90811615158352600f546020840152601054161515828401528251608081019093525f928392839260609284928492849282850190601160048282826020028201915b81548152602001906001019080831161047d575050509183525050604080516060810191829052602090920191906007840190600390825f855b825461010083900a900460ff1615158152602060019283018181049485019490930390920291018084116104b757505050929093525050505060208101518151608083015151601c54601a54939b50919950975060e81b94509091506001600160401b0381111561052a5761052a61125d565b60405190808252806020026020018201604052801561055d57816020015b60608152602001906001900390816105485790505b5093505f5b601a5481101561063357601a818154811061057f5761057f6114d8565b905f5260205f20018054610592906114ec565b80601f01602080910402602001604051908101604052809291908181526020018280546105be906114ec565b80156106095780601f106105e057610100808354040283529160200191610609565b820191905f5260205f20905b8154815290600101906020018083116105ec57829003601f168201915b5050505050858281518110610620576106206114d8565b6020908102919091010152600101610562565b506019546001600160401b0381111561064e5761064e61125d565b604051908082528060200260200182016040528015610677578160200160208202803683370190505b5091505f5b6019548110156106c75760198181548110610699576106996114d8565b905f5260205f2001548382815181106106b4576106b46114d8565b602090810291909101015260010161067c565b5050909192939495565b600180546106de906114ec565b80601f016020809104026020016040519081016040528092919081815260200182805461070a906114ec565b80156107555780601f1061072c57610100808354040283529160200191610755565b820191905f5260205f20905b81548152906001019060200180831161073857829003601f168201915b505050505081565b6040516315af233b60e31b815260040160405180910390fd5b336001600160a01b037f000000000000000000000000e57f4773bd9c9d8b6cd70431117d353298b9f5bf16146107bf57604051635c427cd960e01b815260040160405180910390fd5b5f828060200190518101906107d491906116ad565b90506107e08183610a8b565b505050565b6001600160a01b0382165f90815260056020526040812054801580159061080c5750828111155b9150505b92915050565b601b80546106de906114ec565b6019546060905f906001600160401b038111156108425761084261125d565b60405190808252806020026020018201604052801561086b578160200160208202803683370190505b5090505f5b6019548110156108bb576019818154811061088d5761088d6114d8565b905f5260205f2001548282815181106108a8576108a86114d8565b6020908102919091010152600101610870565b50919050565b600280546106de906114ec565b60208310156108f05760405163a512e2ff60e01b815260040160405180910390fd5b60408110156109125760405163a512e2ff60e01b815260040160405180910390fd5b83355f610922602082858761186d565b61092b91611894565b90505f61093c60406020868861186d565b61094591611894565b90505f610955856040818961186d565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920182905250601654949550939250610995915050565b90505f60025f60081b5f548c8c6040516020016109b69594939291906118b1565b60405160208183030381529060405290507f000000000000000000000000e57f4773bd9c9d8b6cd70431117d353298b9f5bf6001600160a01b031663f7e83aee82848b8b604051602001610a0c939291906118eb565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401610a38929190611904565b5f604051808303815f87803b158015610a4f575f5ffd5b505af1158015610a61573d5f5f3e3d5ffd5b5050505050505050505050505050565b600380546106de906114ec565b600480546106de906114ec565b81515f9081526018602052604090205460ff16610ac657815160405163d4547dd560e01b815260048101919091526024015b60405180910390fd5b6040808301515f8181526017602052919091205460ff1615610afb57604051636569570160e11b815260040160405180910390fd5b60208301516001600160a01b038116610b2757604051632057875960e21b815260040160405180910390fd5b601c5460e81b6001600160e81b03191615610b9f575f610b4a8560e00151610d3b565b601c5490915060e81b6001600160e81b031990811690821614610b9d57601c54604051631c40172160e31b81526001600160e81b031960e89290921b821660048201529082166024820152604401610abd565b505b6001600160a01b0381165f9081526005602052604090205415610bd55760405163b0ca2ff560e01b815260040160405180910390fd5b5f828152601760209081526040808320805460ff191660011790556001600160a01b0384168352600590915281204290556006805491610c1483611945565b90915550506001600160581b600160f81b03605883901b16177f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018110610c915760405162461bcd60e51b8152602060048201526012602482015271496e76616c6964206c6561662076616c756560701b6044820152606401610abd565b610c9c600782610e45565b50610ca5611017565b84516040516001600160a01b038416917f52dcbba5720a8ca5da4e0eed87dfd81e6d1fe4726470a0037a8aba140197959691610ce991878252602082015260400190565b60405180910390a2816001600160a01b03167f2726ce6e3b7987cbbb10c5a55b44725526c540fbba590cfc20afab691fa45edf42604051610d2c91815260200190565b60405180910390a25050505050565b80515f908290600314610d615760405163ceb73e5760e01b815260040160405180910390fd5b6040805160038082528183019092525f916020820181803683370190505090505f5b6003811015610e39575f838281518110610d9f57610d9f6114d8565b016020015160f81c905060618110801590610dbe5750607a8160ff1611155b15610dd157610dce60208261195d565b90505b60418160ff161080610de65750605a8160ff16115b15610e045760405163ceb73e5760e01b815260040160405180910390fd5b8060f81b838381518110610e1a57610e1a6114d8565b60200101906001600160f81b03191690815f1a90535050600101610d83565b50602001519392505050565b5f7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018210610e86576040516361c0541760e11b815260040160405180910390fd5b815f03610ea6576040516314b48df160e11b815260040160405180910390fd5b5f82815260038401602052604090205415610ed4576040516312c50cad60e11b815260040160405180910390fd5b825460018085015490610ee8908390611976565b610ef3826002611a6c565b1015610f0557610f0281611945565b90505b60018501819055835f5b82811015610fdd578084901c600116600103610fc2576040805180820182525f83815260028a0160209081529083902054825281018490529051632b0aac7f60e11b81527390077cab41b84d4dd0bb311b1c820da0741d47269163561558fe91610f7c9190600401611a77565b602060405180830381865af4158015610f97573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fbb9190611aa7565b9150610fd5565b5f81815260028801602052604090208290555b600101610f0f565b50610fe783611945565b8087555f928352600287016020908152604080852084905596845260039097019096529390209390935550919050565b6008545f9081526009602052604090205480611034600b8261109a565b5f818152600d6020908152604091829020805467ffffffffffffffff1916436001600160401b03811691909117909155915191825283917fac84e1f746682c16ccc7cac6060f24ba0d81b110e6dc4cfa95bbfae24a5fc07d910160405180910390a25050565b81545f9083826110a983611945565b9091555060018401805491925083906110cb906110c68486611abe565b6110d2565b5550505050565b5f8261080c6110ee846110ea845f9081526020902090565b0190565b90565b80356001600160a01b0381168114611107575f5ffd5b919050565b5f6020828403121561111c575f5ffd5b611125826110f1565b9392505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b5f8151808452602084019350602083015f5b8281101561118a57815186526020958601959091019060010161116c565b5093949350505050565b5f60c082018883528715156020840152861515604084015260c0606084015280865180835260e08501915060e08160051b8601019250602088015f5b828110156112015760df198786030184526111ec85835161112c565b945060209384019391909101906001016111d0565b5050506001600160e81b0319861660808501525082810360a0840152611227818561115a565b9998505050505050505050565b5f60208284031215611244575f5ffd5b5035919050565b602081525f611125602083018461112c565b634e487b7160e01b5f52604160045260245ffd5b6040516101a081016001600160401b03811182821017156112945761129461125d565b60405290565b604051601f8201601f191681016001600160401b03811182821017156112c2576112c261125d565b604052919050565b5f6001600160401b038211156112e2576112e261125d565b50601f01601f191660200190565b5f82601f8301126112ff575f5ffd5b813561131261130d826112ca565b61129a565b818152846020838601011115611326575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f5f60408385031215611353575f5ffd5b82356001600160401b03811115611368575f5ffd5b611374858286016112f0565b92505060208301356001600160401b0381111561138f575f5ffd5b61139b858286016112f0565b9150509250929050565b5f5f604083850312156113b6575f5ffd5b6113bf836110f1565b946020939093013593505050565b5f5f5f606084860312156113df575f5ffd5b833592506020840135915060408401356001600160401b03811115611402575f5ffd5b61140e868287016112f0565b9150509250925092565b602081525f611125602083018461115a565b5f5f83601f84011261143a575f5ffd5b5081356001600160401b03811115611450575f5ffd5b602083019150836020828501011115611467575f5ffd5b9250929050565b5f5f5f5f60408587031215611481575f5ffd5b84356001600160401b03811115611496575f5ffd5b6114a28782880161142a565b90955093505060208501356001600160401b038111156114c0575f5ffd5b6114cc8782880161142a565b95989497509550505050565b634e487b7160e01b5f52603260045260245ffd5b600181811c9082168061150057607f821691505b6020821081036108bb57634e487b7160e01b5f52602260045260245ffd5b5f82601f83011261152d575f5ffd5b611537608061129a565b806080840185811115611548575f5ffd5b845b8181101561156257805184526020938401930161154a565b509095945050505050565b5f82601f83011261157c575f5ffd5b815161158a61130d826112ca565b81815284602083860101111561159e575f5ffd5b8160208501602083015e5f918101602001919091529392505050565b5f82601f8301126115c9575f5ffd5b81516001600160401b038111156115e2576115e261125d565b8060051b6115f26020820161129a565b9182526020818501810192908101908684111561160d575f5ffd5b6020860192505b838310156116525782516001600160401b03811115611631575f5ffd5b611640886020838a010161156d565b83525060209283019290910190611614565b9695505050505050565b5f82601f83011261166b575f5ffd5b611675606061129a565b806060840185811115611686575f5ffd5b845b81811015611562578051801515811461169f575f5ffd5b845260209384019301611688565b5f602082840312156116bd575f5ffd5b81516001600160401b038111156116d2575f5ffd5b820161024081850312156116e4575f5ffd5b6116ec611271565b815181526020808301519082015260408083015190820152611711856060840161151e565b606082015260e08201516001600160401b0381111561172e575f5ffd5b61173a8682850161156d565b6080830152506101008201516001600160401b03811115611759575f5ffd5b611765868285016115ba565b60a0830152506101208201516001600160401b03811115611784575f5ffd5b6117908682850161156d565b60c0830152506101408201516001600160401b038111156117af575f5ffd5b6117bb8682850161156d565b60e0830152506101608201516001600160401b038111156117da575f5ffd5b6117e68682850161156d565b610100830152506101808201516001600160401b03811115611806575f5ffd5b6118128682850161156d565b610120830152506101a08201516001600160401b03811115611832575f5ffd5b61183e8682850161156d565b610140830152506101c082015161016082015261185f856101e0840161165c565b610180820152949350505050565b5f5f8585111561187b575f5ffd5b83861115611887575f5ffd5b5050820193919092039150565b80356020831015610810575f19602084900360031b1b1692915050565b60f886901b6001600160f81b031916815260ff198516600182015260208101849052818360408301375f9101604001908152949350505050565b838152818360208301375f910160200190815292915050565b604081525f611916604083018561112c565b8281036020840152611928818561112c565b95945050505050565b634e487b7160e01b5f52601160045260245ffd5b5f6001820161195657611956611931565b5060010190565b60ff828116828216039081111561081057610810611931565b8082018082111561081057610810611931565b6001815b60018411156119c4578085048111156119a8576119a8611931565b60018416156119b657908102905b60019390931c92800261198d565b935093915050565b5f826119da57506001610810565b816119e657505f610810565b81600181146119fc5760028114611a0657611a22565b6001915050610810565b60ff841115611a1757611a17611931565b50506001821b610810565b5060208310610133831016604e8410600b8410161715611a45575081810a610810565b611a515f198484611989565b805f1904821115611a6457611a64611931565b029392505050565b5f61112583836119cc565b6040810181835f5b6002811015611a9e578151835260209283019290910190600101611a7f565b50505092915050565b5f60208284031215611ab7575f5ffd5b5051919050565b5f82611ad857634e487b7160e01b5f52601260045260245ffd5b50069056fea2646970667358221220a251cdb6128c837b3e67a0462fe7a77714364cf72afd6c00522e8e2f7825463b64736f6c634300081c0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000e57f4773bd9c9d8b6cd70431117d353298b9f5bf00000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000176d616e69666573746f2d636c65616e2d7374726565747300000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000031436f6c6c6563746976652046726565646f6d3a2041204d616e69666573746f20666f722050617274696369706174696f6e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016444156494e43492e766f746520436f6d6d756e69747900000000000000000000000000000000000000000000000000000000000000000000000000000000000a323032352d31312d31360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006d52320436f6c6c6563746976652046726565646f6d3a2041204d616e69666573746f20666f722050617274696369706174696f6e0a0a576520776572652070726f6d697365642064656d6f63726163792e0a5768617420776520676f7420776173207065726d697373696f6e2e0a5065726d697373696f6e20746f2063686f6f7365206265747765656e206f7074696f6e73207765206469646e2774206372656174652e0a5065726d697373696f6e20746f20737065616b206f6e6c79207768656e2073706f6b656e20746f2e0a0a5065726d697373696f6e20746f20657869737420696e736964652073797374656d73206275696c7420746f20636f6e7461696e2075732e0a5468657920746f6c642075732074686973207761732066726565646f6d2e0a4275742066726565646f6d20776974686f7574206167656e637920697320746865617465722e0a5765207363726f6c6c2e20576520766f74652e205765207369676e207065746974696f6e732e0a416e64207374696c6c2c2074686520776f726c64206275726e732c20696e657175616c6974792067726f77732c20616e6420747275737420636f6c6c61707365732e0a54686520746872656164732074686174206f6e63652068656c6420757320746f676574686572206172652074656172696e672061706172742e0a2a2a456e6f7567682e2a2a0a0a57652072656675736520746f207369742071756965746c79207768696c65206f746865727320646563696465206f7572206675747572652e0a57652072656675736520746f206d697374616b6520726570726573656e746174696f6e20666f722070617274696369706174696f6e2e0a5468652073797374656d732074686174206661696c656420757320617265206e6f7420746865206f6e6c79206f6e6573207765206861766520746f206c6976652062792e0a46726565646f6d20626567696e7320776974682070617274696369706174696f6e2c206e6f74206f62656469656e63652e0a0a45766572792068756d616e206465736572766573206120766f69636520696e207468652073797374656d73207468657920646570656e64206f6e2c0a74686520706c6174666f726d732074686579207573652c2074686520706f6c69636965732074686174207368617065207468656d2c0a746865206675747572652074686579276c6c20696e68657269742e0a0a2a2a57652062656c696576652070726976616379206973206e6f74206120666561747572652c2069742773206120666f756e646174696f6e2e2a2a0a54686520726967687420746f2065786973742c207468696e6b2c20616e6420636f6e6e65637420776974686f7574207375727665696c6c616e63652e0a50726976616379206973207468652073706163652077686572652064697373656e742c20637265617469766974792c20616e642064656d6f63726163792061726520626f726e2e0a0a2a2a57652062656c6965766520617574686f72697479206d757374206265206163636f756e7461626c652c20616e6420706f776572207472616e73706172656e742e2a2a0a476f7665726e616e6365206973206e6f7420736f6d657468696e6720646f6e6520746f2075733b206974277320736f6d657468696e6720776520646f2c20746f6765746865722e0a0a2a2a57652062656c6965766520746563686e6f6c6f6779206973206120746f6f6c2c206e6f742061206d61737465722e2a2a0a4c696b65206c616e67756167652c206974206d7573742062656c6f6e6720746f2065766572796f6e652c0a61207075626c696320676f6f6420746f206275696c642074727573742c206e6f7420657874726163742069742e0a0a57652062656c6965766520696e2073656c662d736f7665726569676e20696e6672617374727563747572652c0a7472616e73706172656e63792061732074727574682c0a616e6420636f6c6c61626f726174696f6e20617320737472656e6774682e0a0a23202a2a57652061726520746865206275696c64657273206f662074686520636f6d6d6f6e732e2a2a0a5468652070656f706c652077686f2072656675736520746f2072656d61696e206f6e2074686520736964656c696e65732e0a54686520647265616d6572732077686f207475726e206672757374726174696f6e20696e746f20696e76656e74696f6e2e0a54686520636f6d6d756e69746965732077686f207475726e20696465617320696e746f20616374696f6e2e0a0a2a2a426563617573652074686520667574757265207765206c69766520696e20646570656e6473206f6e2074686520676f7665726e616e6365207765206163686965766520746f6461792e2a2a0a2a2a23436f6c6c65637469766546726565646f6d2a2a0a0000000000000000000000

-----Decoded View---------------
Arg [0] : identityVerificationHubV2Address (address): 0xe57F4773bd9c9d8b6Cd70431117d353298B9f5BF
Arg [1] : scopeSeed (string): manifesto-clean-streets
Arg [2] : unformattedVerificationConfig (tuple):
Arg [1] : olderThan (uint256): 16

Arg [3] : attestationAllowList (bytes32[]): System.Byte[],System.Byte[]
Arg [4] : requiredNationalityInput (string):
Arg [5] : metadata (tuple):
Arg [1] : title (string): Collective Freedom: A Manifesto for Participation
Arg [2] : authors (string): DAVINCI.vote Community
Arg [3] : date (string): 2025-11-16
Arg [4] : manifestoText (string): # Collective Freedom: A Manifesto for Participation We were promised democracy. What we got was permission. Permission to choose between options we didn't create. Permission to speak only when spoken to. Permission to exist inside systems built to contain us. They told us this was freedom. But freedom without agency is theater. We scroll. We vote. We sign petitions. And still, the world burns, inequality grows, and trust collapses. The threads that once held us together are tearing apart. **Enough.** We refuse to sit quietly while others decide our future. We refuse to mistake representation for participation. The systems that failed us are not the only ones we have to live by. Freedom begins with participation, not obedience. Every human deserves a voice in the systems they depend on, the platforms they use, the policies that shape them, the future they'll inherit. **We believe privacy is not a feature, it's a foundation.** The right to exist, think, and connect without surveillance. Privacy is the space where dissent, creativity, and democracy are born. **We believe authority must be accountable, and power transparent.** Governance is not something done to us; it's something we do, together. **We believe technology is a tool, not a master.** Like language, it must belong to everyone, a public good to build trust, not extract it. We believe in self-sovereign infrastructure, transparency as truth, and collaboration as strength. # **We are the builders of the commons.** The people who refuse to remain on the sidelines. The dreamers who turn frustration into invention. The communities who turn ideas into action. **Because the future we live in depends on the governance we achieve today.** **#CollectiveFreedom**


-----Encoded View---------------
83 Constructor Arguments found :
Arg [0] : 000000000000000000000000e57f4773bd9c9d8b6cd70431117d353298b9f5bf
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000180
Arg [4] : 00000000000000000000000000000000000000000000000000000000000001e0
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000200
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000017
Arg [7] : 6d616e69666573746f2d636c65616e2d73747265657473000000000000000000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000010
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [14] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [15] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [16] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [17] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [18] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [19] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [20] : 0000000000000000000000000000000000000000000000000000000000000031
Arg [21] : 436f6c6c6563746976652046726565646f6d3a2041204d616e69666573746f20
Arg [22] : 666f722050617274696369706174696f6e000000000000000000000000000000
Arg [23] : 0000000000000000000000000000000000000000000000000000000000000016
Arg [24] : 444156494e43492e766f746520436f6d6d756e69747900000000000000000000
Arg [25] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [26] : 323032352d31312d313600000000000000000000000000000000000000000000
Arg [27] : 00000000000000000000000000000000000000000000000000000000000006d5
Arg [28] : 2320436f6c6c6563746976652046726565646f6d3a2041204d616e6966657374
Arg [29] : 6f20666f722050617274696369706174696f6e0a0a576520776572652070726f
Arg [30] : 6d697365642064656d6f63726163792e0a5768617420776520676f7420776173
Arg [31] : 207065726d697373696f6e2e0a5065726d697373696f6e20746f2063686f6f73
Arg [32] : 65206265747765656e206f7074696f6e73207765206469646e27742063726561
Arg [33] : 74652e0a5065726d697373696f6e20746f20737065616b206f6e6c7920776865
Arg [34] : 6e2073706f6b656e20746f2e0a0a5065726d697373696f6e20746f2065786973
Arg [35] : 7420696e736964652073797374656d73206275696c7420746f20636f6e746169
Arg [36] : 6e2075732e0a5468657920746f6c642075732074686973207761732066726565
Arg [37] : 646f6d2e0a4275742066726565646f6d20776974686f7574206167656e637920
Arg [38] : 697320746865617465722e0a5765207363726f6c6c2e20576520766f74652e20
Arg [39] : 5765207369676e207065746974696f6e732e0a416e64207374696c6c2c207468
Arg [40] : 6520776f726c64206275726e732c20696e657175616c6974792067726f77732c
Arg [41] : 20616e6420747275737420636f6c6c61707365732e0a54686520746872656164
Arg [42] : 732074686174206f6e63652068656c6420757320746f67657468657220617265
Arg [43] : 2074656172696e672061706172742e0a2a2a456e6f7567682e2a2a0a0a576520
Arg [44] : 72656675736520746f207369742071756965746c79207768696c65206f746865
Arg [45] : 727320646563696465206f7572206675747572652e0a57652072656675736520
Arg [46] : 746f206d697374616b6520726570726573656e746174696f6e20666f72207061
Arg [47] : 7274696369706174696f6e2e0a5468652073797374656d732074686174206661
Arg [48] : 696c656420757320617265206e6f7420746865206f6e6c79206f6e6573207765
Arg [49] : 206861766520746f206c6976652062792e0a46726565646f6d20626567696e73
Arg [50] : 20776974682070617274696369706174696f6e2c206e6f74206f62656469656e
Arg [51] : 63652e0a0a45766572792068756d616e206465736572766573206120766f6963
Arg [52] : 6520696e207468652073797374656d73207468657920646570656e64206f6e2c
Arg [53] : 0a74686520706c6174666f726d732074686579207573652c2074686520706f6c
Arg [54] : 69636965732074686174207368617065207468656d2c0a746865206675747572
Arg [55] : 652074686579276c6c20696e68657269742e0a0a2a2a57652062656c69657665
Arg [56] : 2070726976616379206973206e6f74206120666561747572652c206974277320
Arg [57] : 6120666f756e646174696f6e2e2a2a0a54686520726967687420746f20657869
Arg [58] : 73742c207468696e6b2c20616e6420636f6e6e65637420776974686f75742073
Arg [59] : 75727665696c6c616e63652e0a50726976616379206973207468652073706163
Arg [60] : 652077686572652064697373656e742c20637265617469766974792c20616e64
Arg [61] : 2064656d6f63726163792061726520626f726e2e0a0a2a2a57652062656c6965
Arg [62] : 766520617574686f72697479206d757374206265206163636f756e7461626c65
Arg [63] : 2c20616e6420706f776572207472616e73706172656e742e2a2a0a476f766572
Arg [64] : 6e616e6365206973206e6f7420736f6d657468696e6720646f6e6520746f2075
Arg [65] : 733b206974277320736f6d657468696e6720776520646f2c20746f6765746865
Arg [66] : 722e0a0a2a2a57652062656c6965766520746563686e6f6c6f67792069732061
Arg [67] : 20746f6f6c2c206e6f742061206d61737465722e2a2a0a4c696b65206c616e67
Arg [68] : 756167652c206974206d7573742062656c6f6e6720746f2065766572796f6e65
Arg [69] : 2c0a61207075626c696320676f6f6420746f206275696c642074727573742c20
Arg [70] : 6e6f7420657874726163742069742e0a0a57652062656c6965766520696e2073
Arg [71] : 656c662d736f7665726569676e20696e6672617374727563747572652c0a7472
Arg [72] : 616e73706172656e63792061732074727574682c0a616e6420636f6c6c61626f
Arg [73] : 726174696f6e20617320737472656e6774682e0a0a23202a2a57652061726520
Arg [74] : 746865206275696c64657273206f662074686520636f6d6d6f6e732e2a2a0a54
Arg [75] : 68652070656f706c652077686f2072656675736520746f2072656d61696e206f
Arg [76] : 6e2074686520736964656c696e65732e0a54686520647265616d657273207768
Arg [77] : 6f207475726e206672757374726174696f6e20696e746f20696e76656e74696f
Arg [78] : 6e2e0a54686520636f6d6d756e69746965732077686f207475726e2069646561
Arg [79] : 7320696e746f20616374696f6e2e0a0a2a2a4265636175736520746865206675
Arg [80] : 74757265207765206c69766520696e20646570656e6473206f6e207468652067
Arg [81] : 6f7665726e616e6365207765206163686965766520746f6461792e2a2a0a2a2a
Arg [82] : 23436f6c6c65637469766546726565646f6d2a2a0a0000000000000000000000


Block Transaction Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
0xa4d9c19de4881876B14d3C682f79634e2785b2f7
Loading...
Loading
Loading...
Loading
Loading...
Loading

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.