Base Sepolia Testnet

Contract

0x094FCC095323080e71a037b2B1e3519c07dd84F8
Source Code Source Code

Overview

ETH Balance

0 ETH

More Info

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Amount
Execute389537722026-03-16 15:43:5229 days ago1773675832IN
0x094FCC09...c07dd84F8
0 ETH0.000003410.006
Execute389537392026-03-16 15:42:4629 days ago1773675766IN
0x094FCC09...c07dd84F8
0 ETH0.000003440.006
Execute389537082026-03-16 15:41:4429 days ago1773675704IN
0x094FCC09...c07dd84F8
0 ETH0.000003470.006
Execute389536052026-03-16 15:38:1829 days ago1773675498IN
0x094FCC09...c07dd84F8
0 ETH0.000003330.006
Execute389535912026-03-16 15:37:5029 days ago1773675470IN
0x094FCC09...c07dd84F8
0 ETH0.000003330.006
Execute389535412026-03-16 15:36:1029 days ago1773675370IN
0x094FCC09...c07dd84F8
0 ETH0.000003360.006
Execute389535202026-03-16 15:35:2829 days ago1773675328IN
0x094FCC09...c07dd84F8
0 ETH0.000003330.006
Execute389534612026-03-16 15:33:3029 days ago1773675210IN
0x094FCC09...c07dd84F8
0 ETH0.000003360.006
Execute370021702026-01-30 11:30:2874 days ago1769772628IN
0x094FCC09...c07dd84F8
0 ETH0.000006840.00120006
Execute369220372026-01-28 14:59:2276 days ago1769612362IN
0x094FCC09...c07dd84F8
0 ETH0.000000730.0012
Execute369220062026-01-28 14:58:2076 days ago1769612300IN
0x094FCC09...c07dd84F8
0 ETH0.000000760.0012
Execute369218932026-01-28 14:54:3476 days ago1769612074IN
0x094FCC09...c07dd84F8
0 ETH0.000000840.0012
Execute369216952026-01-28 14:47:5876 days ago1769611678IN
0x094FCC09...c07dd84F8
0 ETH0.000002030.0012
Execute368767972026-01-27 13:51:2277 days ago1769521882IN
0x094FCC09...c07dd84F8
0 ETH0.000000960.0012

Latest 1 internal transaction

Parent Transaction Hash Block From To Amount
368751852026-01-27 12:57:3877 days ago1769518658  Contract Creation0 ETH

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ProtocolAdapter

Compiler Version
v0.8.33+commit.64118f21

Optimization Enabled:
Yes with 10000 runs

Other Settings:
osaka EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

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

import {Ownable} from "@openzeppelin-contracts-5.5.0/access/Ownable.sol";
import {Pausable} from "@openzeppelin-contracts-5.5.0/utils/Pausable.sol";
import {ReentrancyGuardTransient} from "@openzeppelin-contracts-5.5.0/utils/ReentrancyGuardTransient.sol";
import {RiscZeroVerifierRouter} from "risc0-risc0-ethereum-3.0.1/contracts/src/RiscZeroVerifierRouter.sol";

import {IForwarder} from "./interfaces/IForwarder.sol";
import {IProtocolAdapter} from "./interfaces/IProtocolAdapter.sol";
import {IVersion} from "./interfaces/IVersion.sol";

import {MerkleTree} from "./libs/MerkleTree.sol";
import {Aggregation} from "./libs/proving/Aggregation.sol";
import {Compliance} from "./libs/proving/Compliance.sol";
import {Delta} from "./libs/proving/Delta.sol";
import {Logic} from "./libs/proving/Logic.sol";
import {RiscZeroUtils} from "./libs/RiscZeroUtils.sol";
import {TagUtils} from "./libs/TagUtils.sol";
import {Versioning} from "./libs/Versioning.sol";

import {CommitmentTree} from "./state/CommitmentTree.sol";
import {NullifierSet} from "./state/NullifierSet.sol";
import {Action, Transaction} from "./Types.sol";

/// @title ProtocolAdapter
/// @author Anoma Foundation, 2025
/// @notice The protocol adapter contract verifying and executing resource machine transactions.
/// @custom:security-contact [email protected]
contract ProtocolAdapter is
    IProtocolAdapter,
    IVersion,
    ReentrancyGuardTransient,
    Ownable,
    Pausable,
    CommitmentTree,
    NullifierSet
{
    using Delta for Delta.Point;
    using Logic for Logic.VerifierInput[];
    using Logic for Logic.VerifierInput;
    using MerkleTree for bytes32[];
    using RiscZeroUtils for Aggregation.Instance;
    using RiscZeroUtils for Compliance.Instance;
    using RiscZeroUtils for Logic.Instance;
    using TagUtils for Action;
    using TagUtils for Transaction;

    /// @notice A data structure containing general and proof aggregation-related internal variables being updated while
    /// iterating over the actions and compliance units during the `execute` function call.
    /// @param tags A variable to aggregate tags over the actions.
    /// @param logicRefs A variable to aggregate logic references over the actions.
    /// @param latestCommitmentTreeRoot The latest commitment tree root to be stored in the set of historical roots at
    /// the end of the `execute` function call.
    /// @param transactionDelta A variable to aggregate the unit deltas over the actions.
    /// @param tagCounter A counter representing the index of the next resource tag to visit.
    /// @param skipRiscZeroProofVerification Whether to skip RISC Zero proof verification or not.
    /// @param isProofAggregated Whether the transaction to execute contains an aggregated proof or not.
    /// @param complianceInstances A variable to aggregate RISC Zero compliance proof instances.
    /// @param logicInstances A variable to aggregate RISC Zero logic proof instances.
    struct InternalVariables {
        /* General variables */
        bytes32[] tags;
        bytes32[] logicRefs;
        bytes32 latestCommitmentTreeRoot;
        Delta.Point transactionDelta;
        uint256 tagCounter;
        /* Proof verification-related variables */
        bool skipRiscZeroProofVerification;
        /* Proof aggregation-related variables */
        bool isProofAggregated;
        Compliance.Instance[] complianceInstances;
        Logic.Instance[] logicInstances;
    }

    RiscZeroVerifierRouter internal immutable _TRUSTED_RISC_ZERO_VERIFIER_ROUTER;
    bytes4 internal immutable _RISC_ZERO_VERIFIER_SELECTOR;

    error ZeroNotAllowed();
    error ForwarderCallOutputMismatch(bytes expected, bytes actual);
    error LogicRefMismatch(bytes32 expected, bytes32 actual);
    error RiscZeroVerifierSelectorMismatch(bytes4 expected, bytes4 actual);
    error RiscZeroVerifierStopped();
    error Simulated(uint256 gasUsed);

    /// @notice Constructs the protocol adapter contract.
    /// @param riscZeroVerifierRouter The RISC Zero verifier router contract.
    /// @param riscZeroVerifierSelector The RISC Zero verifier selector this protocol adapter is associated with.
    /// @param emergencyStopCaller The account that can stop the protocol adapter in case of a vulnerability.
    constructor(
        RiscZeroVerifierRouter riscZeroVerifierRouter,
        bytes4 riscZeroVerifierSelector,
        address emergencyStopCaller
    ) Ownable(emergencyStopCaller) {
        if (address(riscZeroVerifierRouter) == address(0)) {
            revert ZeroNotAllowed();
        }

        _TRUSTED_RISC_ZERO_VERIFIER_ROUTER = riscZeroVerifierRouter;
        _RISC_ZERO_VERIFIER_SELECTOR = riscZeroVerifierSelector;

        // Sanity check that the verifier has not been stopped already.
        if (isEmergencyStopped()) {
            revert RiscZeroVerifierStopped();
        }
    }

    /// @inheritdoc IProtocolAdapter
    function execute(Transaction calldata transaction) external override {
        _execute({transaction: transaction, skipRiscZeroProofVerification: false});
    }

    /// @inheritdoc IProtocolAdapter
    function simulateExecute(Transaction calldata transaction, bool skipRiscZeroProofVerification) external override {
        uint256 gasStart = gasleft();

        _execute({transaction: transaction, skipRiscZeroProofVerification: skipRiscZeroProofVerification});

        revert Simulated({gasUsed: gasStart - gasleft()});
    }

    /// @inheritdoc IProtocolAdapter
    function emergencyStop() external override onlyOwner whenNotPaused {
        _pause();
    }

    /// @inheritdoc IVersion
    function getVersion() external pure override returns (bytes32 version) {
        version = Versioning._PROTOCOL_ADAPTER_VERSION;
    }

    /// @inheritdoc IProtocolAdapter
    function isEmergencyStopped() public view override returns (bool isStopped) {
        bool risc0Paused =
            Pausable(address(_TRUSTED_RISC_ZERO_VERIFIER_ROUTER.getVerifier(getRiscZeroVerifierSelector()))).paused();

        isStopped = risc0Paused || paused();
    }

    /// @inheritdoc IProtocolAdapter
    function getRiscZeroVerifierRouter() public view override returns (address verifierRouter) {
        verifierRouter = address(_TRUSTED_RISC_ZERO_VERIFIER_ROUTER);
    }

    /// @inheritdoc IProtocolAdapter
    function getRiscZeroVerifierSelector() public view override returns (bytes4 verifierSelector) {
        verifierSelector = _RISC_ZERO_VERIFIER_SELECTOR;
    }

    /// @notice Executes a transaction by adding the commitments and nullifiers to the commitment tree and nullifier
    /// set, respectively.
    /// @param transaction The transaction to execute.
    /// @param skipRiscZeroProofVerification Whether to skip RISC Zero proof verification or not.
    /// @dev This function cannot be called anymore once `emergencyStop()` has been called.
    function _execute(Transaction calldata transaction, bool skipRiscZeroProofVerification)
        internal
        nonReentrant
        whenNotPaused
    {
        InternalVariables memory vars = _initializeVars(transaction, skipRiscZeroProofVerification);

        uint256 actionCount = transaction.actions.length;
        for (uint256 i = 0; i < actionCount; ++i) {
            Action calldata action = transaction.actions[i];

            // The action tree root is placed in the resource logic instance, informing a resource of all the
            // created and consumed resources in the same action.
            bytes32 actionTreeRoot = action.collectTags().computeRoot();

            uint256 complianceUnitCount = action.complianceVerifierInputs.length;
            for (uint256 j = 0; j < complianceUnitCount; ++j) {
                Compliance.VerifierInput calldata complianceVerifierInput = action.complianceVerifierInputs[j];

                // Process the compliance related checks and proofs.
                vars = _processCompliance({input: complianceVerifierInput, vars: vars});

                // Process the logic proof of the consumed resource.
                vars = _processLogic({
                    isConsumed: true,
                    // The `lookup` function reverts if the nullifier is not part of the logic verifier inputs.
                    input: action.logicVerifierInputs.lookup(complianceVerifierInput.instance.consumed.nullifier),
                    logicRefFromComplianceUnit: complianceVerifierInput.instance.consumed.logicRef,
                    actionTreeRoot: actionTreeRoot,
                    vars: vars
                });

                // Process the logic proof of the created resource.
                vars = _processLogic({
                    isConsumed: false,
                    // The `lookup` function reverts if the commitment is not part of the logic verifier inputs.
                    input: action.logicVerifierInputs.lookup(complianceVerifierInput.instance.created.commitment),
                    logicRefFromComplianceUnit: complianceVerifierInput.instance.created.logicRef,
                    actionTreeRoot: actionTreeRoot,
                    vars: vars
                });

                // After all tags in the action are looked up, we are ensured that the logic verifier input tags are
                // a subset of the tags as presented in the compliance unit.

                // Add the unit delta to the transaction delta.
                vars.transactionDelta = vars.transactionDelta
                    .add(
                        Delta.Point({
                            x: uint256(complianceVerifierInput.instance.unitDeltaX),
                            y: uint256(complianceVerifierInput.instance.unitDeltaY)
                        })
                    );
            }
            emit ActionExecuted({actionTreeRoot: actionTreeRoot, actionTagCount: action.logicVerifierInputs.length});
        }

        // Check if the transaction induces a state change.
        if (vars.tagCounter > 0) {
            // Verify the delta proof and, optionally, the aggregation proof, if it is present.
            _verifyGlobalProofs({
                deltaProof: transaction.deltaProof, aggregationProof: transaction.aggregationProof, vars: vars
            });

            // Store the final commitment tree root.
            _addCommitmentTreeRoot(vars.latestCommitmentTreeRoot);
        }

        // Emit the event containing the transaction and new root.
        emit TransactionExecuted({tags: vars.tags, logicRefs: vars.logicRefs});
    }

    /// @notice Processes a resource logic proof by
    /// * checking that the logic reference matches the one with the corresponding tag in the compliance unit,
    /// * aggregating the logic instance OR verifying the RISC Zero logic proof,
    /// * executing external forwarder calls,
    /// * adding the consumed or created resource tag to the commitment tree or nullifier set,
    /// * emitting the blobs contained in the app data payloads, and
    /// * updating the internal variables
    ///   * adding the tag to the `tags `array
    ///   * adding the logic reference to the `logicRefs` array
    ///   * incrementing the tag counter
    ///   * updating the current commitment tree root
    /// @param isConsumed Whether the logic belongs to a consumed or created resource.
    /// @param input The logic verifier input.
    /// @param logicRefFromComplianceUnit The logic references as found in the corresponding compliance unit.
    /// @param actionTreeRoot The action tree root.
    /// @param vars Internal variables to read from.
    /// @return updatedVars The updated internal variables.
    function _processLogic(
        bool isConsumed,
        Logic.VerifierInput calldata input,
        bytes32 logicRefFromComplianceUnit,
        bytes32 actionTreeRoot,
        InternalVariables memory vars
    ) internal returns (InternalVariables memory updatedVars) {
        updatedVars = vars;

        // In this RM implementation the logicRef is the verifying key.
        bytes32 logicRef = input.verifyingKey;

        // Check that the logic reference from the logic verifier input matches the expected reference from the
        // compliance unit.
        if (logicRef != logicRefFromComplianceUnit) {
            revert LogicRefMismatch({expected: logicRefFromComplianceUnit, actual: logicRef});
        }

        {
            // Obtain the logic instance from the verifier input, action tree root, and consumed flag.
            Logic.Instance memory instance = input.toInstance({actionTreeRoot: actionTreeRoot, isConsumed: isConsumed});

            if (updatedVars.isProofAggregated) {
                // Aggregate the logic instance.
                updatedVars.logicInstances[updatedVars.tagCounter] = instance;
            } else {
                _checkSelector({selector: bytes4(input.proof[0:4])});

                if (!updatedVars.skipRiscZeroProofVerification) {
                    // Verify the logic proof.
                    // slither-disable-next-line calls-loop
                    _TRUSTED_RISC_ZERO_VERIFIER_ROUTER.verify({
                        seal: input.proof, imageId: logicRef, journalDigest: sha256(instance.toJournal())
                    });
                }
            }
        }

        _executeForwarderCalls(input);

        bytes32 tag = input.tag;
        // Populate the tags array for use as a verification key for the delta proof.
        // Note that the order of the compliance units dictate the delta verifying key.
        updatedVars.tags[updatedVars.tagCounter] = tag;

        // Populate an array containing all the logic references.
        // This is used both for events and aggregation proofs.
        updatedVars.logicRefs[updatedVars.tagCounter++] = logicRef;

        // Transition the resource machine state.
        if (isConsumed) {
            // The function reverts if a repeating tag is added to the set.
            // If the final nullifier stored in the action gets added to the set successfully,
            // the compliance units partition the action.
            _addNullifier(tag);
        } else {
            // `_addCommitment` does not error if a repeating leaf is added to the tree.
            // Uniqueness of commitments is grated by the compliance circuit, assuming that nullifiers are unique.
            updatedVars.latestCommitmentTreeRoot = _addCommitment(tag);
        }

        _emitAppDataBlobs(input);
    }

    /// @notice Processes forwarder calls by verifying and executing them.
    /// @param verifierInput The logic verifier input of a resource making the call.
    function _executeForwarderCalls(Logic.VerifierInput calldata verifierInput) internal {
        uint256 nCalls = verifierInput.appData.externalPayload.length;

        for (uint256 i = 0; i < nCalls; ++i) {
            _executeForwarderCall({
                carrierLogicRef: verifierInput.verifyingKey, callBlob: verifierInput.appData.externalPayload[i].blob
            });
        }
    }

    /// @notice Executes a call to a an external, untrusted forwarder contract.
    /// @param carrierLogicRef The logic reference of the carrier resource.
    /// @param callBlob The blob containing the external call instruction.
    /// @dev This function allows arbitrary code execution through the protocol adapter but is constrained through
    /// the associated carrier resource logic.
    function _executeForwarderCall(bytes32 carrierLogicRef, bytes calldata callBlob) internal {
        (address untrustedForwarder, bytes memory input, bytes memory expectedOutput) =
            abi.decode(callBlob, (address, bytes, bytes));

        // slither-disable-next-line calls-loop
        bytes memory actualOutput =
            IForwarder(untrustedForwarder).forwardCall({logicRef: carrierLogicRef, input: input});

        if (keccak256(actualOutput) != keccak256(expectedOutput)) {
            revert ForwarderCallOutputMismatch({expected: expectedOutput, actual: actualOutput});
        }

        // NOTE: The event ordering is protected by the `nonReentrant` modifier on the `execute` function.
        // slither-disable-next-line reentrancy-events
        emit ForwarderCallExecuted({untrustedForwarder: untrustedForwarder, input: input, output: actualOutput});
    }

    /// @notice Emits app data blobs together with the associated resource tag based on their deletion criterion.
    /// @param input The logic verifier input of a resource making the call.
    function _emitAppDataBlobs(Logic.VerifierInput calldata input) internal {
        bytes32 tag = input.tag;

        Logic.ExpirableBlob[] calldata payload = input.appData.resourcePayload;
        uint256 n = payload.length;
        for (uint256 i = 0; i < n; ++i) {
            if (payload[i].deletionCriterion == Logic.DeletionCriterion.Never) {
                // NOTE: The event ordering is protected by the `nonReentrant` modifier on the `execute` function.
                // slither-disable-next-line reentrancy-events
                emit ResourcePayload({tag: tag, index: i, blob: payload[i].blob});
            }
        }

        payload = input.appData.discoveryPayload;
        n = payload.length;
        for (uint256 i = 0; i < n; ++i) {
            if (payload[i].deletionCriterion == Logic.DeletionCriterion.Never) {
                // NOTE: The event ordering is protected by the `nonReentrant` modifier on the `execute` function.
                // slither-disable-next-line reentrancy-events
                emit DiscoveryPayload({tag: tag, index: i, blob: payload[i].blob});
            }
        }

        payload = input.appData.externalPayload;
        n = payload.length;
        for (uint256 i = 0; i < n; ++i) {
            if (payload[i].deletionCriterion == Logic.DeletionCriterion.Never) {
                // NOTE: The event ordering is protected by the `nonReentrant` modifier on the `execute` function.
                // slither-disable-next-line reentrancy-events
                emit ExternalPayload({tag: tag, index: i, blob: payload[i].blob});
            }
        }

        payload = input.appData.applicationPayload;
        n = payload.length;
        for (uint256 i = 0; i < n; ++i) {
            if (payload[i].deletionCriterion == Logic.DeletionCriterion.Never) {
                // NOTE: The event ordering is protected by the `nonReentrant` modifier on the `execute` function.
                // slither-disable-next-line reentrancy-events
                emit ApplicationPayload({tag: tag, index: i, blob: payload[i].blob});
            }
        }
    }

    /// @notice Processes a resource machine compliance proof by
    /// * checking that the commitment tree root references by the consumed resource is in the set of historical roots,
    /// * aggregating the compliance instance OR verifying the RISC Zero compliance proof
    /// @param input The compliance verifier input.
    /// @param vars Internal variables to read from.
    /// @return updatedVars The updated internal variables.
    function _processCompliance(Compliance.VerifierInput calldata input, InternalVariables memory vars)
        internal
        view
        returns (InternalVariables memory updatedVars)
    {
        updatedVars = vars;

        bytes32 root = input.instance.consumed.commitmentTreeRoot;
        if (!_isCommitmentTreeRootContained(root)) {
            revert NonExistingRoot(root);
        }

        if (updatedVars.isProofAggregated) {
            // Aggregate the compliance instance
            updatedVars.complianceInstances[vars.tagCounter / Compliance._RESOURCES_PER_COMPLIANCE_UNIT] =
            input.instance;
        } else {
            _checkSelector({selector: bytes4(input.proof[0:4])});

            if (!updatedVars.skipRiscZeroProofVerification) {
                // Verify the compliance proof.
                // slither-disable-next-line calls-loop
                _TRUSTED_RISC_ZERO_VERIFIER_ROUTER.verify({
                    seal: input.proof,
                    imageId: Compliance._VERIFYING_KEY,
                    journalDigest: sha256(input.instance.toJournal())
                });
            }
        }
    }

    /// @notice Verifies global proofs:
    /// * the mandatory delta proof ensuring that the transaction is balanced,
    /// * the optional aggregation proof if present.
    /// @param deltaProof The delta proof to verify.
    /// @param aggregationProof The aggregation proof to verify if existent.
    /// @param vars Internal variables to read from.
    function _verifyGlobalProofs(
        bytes calldata deltaProof,
        bytes calldata aggregationProof,
        InternalVariables memory vars
    ) internal view {
        // Check the delta proof.
        Delta.verify({
            proof: deltaProof, instance: vars.transactionDelta, verifyingKey: Delta.computeVerifyingKey(vars.tags)
        });

        if (vars.isProofAggregated) {
            _checkSelector({selector: bytes4(aggregationProof[0:4])});

            bytes32 jounalDigest = sha256(
                Aggregation.Instance({
                        logicRefs: vars.logicRefs,
                        complianceInstances: vars.complianceInstances,
                        logicInstances: vars.logicInstances
                    }).toJournal()
            );

            if (!vars.skipRiscZeroProofVerification) {
                // Verify aggregation proof.
                // slither-disable-next-line calls-loop
                _TRUSTED_RISC_ZERO_VERIFIER_ROUTER.verify({
                    seal: aggregationProof, imageId: Aggregation._VERIFYING_KEY, journalDigest: jounalDigest
                });
            }
        }
    }

    /// @notice Checks that a RISC Zero verifier selector matches the one the protocol adapter is associated with.
    /// @param selector The RISC Zero verifier selector to check.
    function _checkSelector(bytes4 selector) internal view {
        if (selector != _RISC_ZERO_VERIFIER_SELECTOR) {
            revert RiscZeroVerifierSelectorMismatch({expected: _RISC_ZERO_VERIFIER_SELECTOR, actual: selector});
        }
    }

    /// @notice Initializes internal variables based on the tag count of the transaction and whether it contains an
    /// aggregation proof or not.
    /// @param transaction The transaction object.
    /// @param skipRiscZeroProofVerification Whether to skip RISC Zero proof verification or not.
    /// @return vars The initialized internal variables.
    function _initializeVars(Transaction calldata transaction, bool skipRiscZeroProofVerification)
        internal
        pure
        returns (InternalVariables memory vars)
    {
        // Compute the tag count.
        //Note that this function ensures that the tag count is a multiple of two.
        uint256 tagCount = transaction.countTags();

        bool isProofAggregated = transaction.aggregationProof.length > 0;

        // Initialize
        vars = InternalVariables({
            /* General variables */
            tags: new bytes32[](tagCount),
            logicRefs: new bytes32[](tagCount),
            latestCommitmentTreeRoot: bytes32(0),
            transactionDelta: Delta.zero(),
            tagCounter: 0,
            /* Proof verification-related variables */
            skipRiscZeroProofVerification: skipRiscZeroProofVerification,
            /* Proof aggregation-related variables */
            isProofAggregated: isProofAggregated,
            complianceInstances: new Compliance
                .Instance[](isProofAggregated ? tagCount / Compliance._RESOURCES_PER_COMPLIANCE_UNIT : 0),
            logicInstances: new Logic.Instance[](isProofAggregated ? tagCount : 0)
        });
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

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

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    bool private _paused;

    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    /**
     * @dev The operation failed because the contract is paused.
     */
    error EnforcedPause();

    /**
     * @dev The operation failed because the contract is not paused.
     */
    error ExpectedPause();

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        if (paused()) {
            revert EnforcedPause();
        }
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        if (!paused()) {
            revert ExpectedPause();
        }
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

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

pragma solidity ^0.8.24;

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

/**
 * @dev Variant of {ReentrancyGuard} that uses transient storage.
 *
 * NOTE: This variant only works on networks where EIP-1153 is available.
 *
 * _Available since v5.1._
 *
 * @custom:stateless
 */
abstract contract ReentrancyGuardTransient {
    using TransientSlot for *;

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant REENTRANCY_GUARD_STORAGE =
        0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    /**
     * @dev A `view` only version of {nonReentrant}. Use to block view functions
     * from being called, preventing reading from inconsistent contract state.
     *
     * CAUTION: This is a "view" modifier and does not change the reentrancy
     * status. Use it only on view functions. For payable or non-payable functions,
     * use the standard {nonReentrant} modifier instead.
     */
    modifier nonReentrantView() {
        _nonReentrantBeforeView();
        _;
    }

    function _nonReentrantBeforeView() private view {
        if (_reentrancyGuardEntered()) {
            revert ReentrancyGuardReentrantCall();
        }
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, REENTRANCY_GUARD_STORAGE.asBoolean().tload() will be false
        _nonReentrantBeforeView();

        // Any calls to nonReentrant after this point will fail
        _reentrancyGuardStorageSlot().asBoolean().tstore(true);
    }

    function _nonReentrantAfter() private {
        _reentrancyGuardStorageSlot().asBoolean().tstore(false);
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _reentrancyGuardStorageSlot().asBoolean().tload();
    }

    function _reentrancyGuardStorageSlot() internal pure virtual returns (bytes32) {
        return REENTRANCY_GUARD_STORAGE;
    }
}

// Copyright 2025 RISC Zero, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.9;

import {Ownable, Ownable2Step} from "openzeppelin/contracts/access/Ownable2Step.sol";

import {IRiscZeroVerifier, Receipt} from "./IRiscZeroVerifier.sol";

/// @notice Router for IRiscZeroVerifier, allowing multiple implementations to be accessible behind a single address.
contract RiscZeroVerifierRouter is IRiscZeroVerifier, Ownable2Step {
    /// @notice Mapping from 4-byte verifier selector to verifier contracts.
    ///         Used to route receipts to verifiers that are able to check the receipt.
    mapping(bytes4 => IRiscZeroVerifier) public verifiers;

    /// @notice Value of an entry that has never been set.
    IRiscZeroVerifier internal constant UNSET = IRiscZeroVerifier(address(0));
    /// @notice A "tombstone" value used to mark verifier entries that have been removed from the mapping.
    IRiscZeroVerifier internal constant TOMBSTONE = IRiscZeroVerifier(address(1));

    /// @notice Error raised when attempting to verify a receipt with a selector that is not
    ///         registered on this router. Generally, this indicates a version mismatch where the
    ///         prover generated a receipt with version of the zkVM that does not match any
    ///         registered version on this router contract.
    error SelectorUnknown(bytes4 selector);
    /// @notice Error raised when attempting to add a verifier for a selector that is already registered.
    error SelectorInUse(bytes4 selector);
    /// @notice Error raised when attempting to verify a receipt with a selector that has been
    ///         removed, or attempting to add a new verifier with a selector that was previously
    ///         registered and then removed.
    error SelectorRemoved(bytes4 selector);
    /// @notice Error raised when attempting to add a verifier with a zero address.
    error VerifierAddressZero();

    constructor(address admin) Ownable(admin) {}

    /// @notice Adds a verifier to the router, such that it can receive receipt verification calls.
    function addVerifier(bytes4 selector, IRiscZeroVerifier verifier) external onlyOwner {
        if (verifiers[selector] == TOMBSTONE) {
            revert SelectorRemoved({selector: selector});
        }
        if (verifiers[selector] != UNSET) {
            revert SelectorInUse({selector: selector});
        }
        if (address(verifier) == address(0)) {
            revert VerifierAddressZero();
        }
        verifiers[selector] = verifier;
    }

    /// @notice Removes verifier from the router, such that it can not receive verification calls.
    ///         Removing a selector sets it to the tombstone value. It can never be set to any
    ///         other value, and can never be reused for a new verifier, in order to enforce the
    ///         property that each selector maps to at most one implementation across time.
    function removeVerifier(bytes4 selector) external onlyOwner {
        // Simple check to reduce the chance of accidents.
        // NOTE: If there ever _is_ a reason to remove a selector that has never been set, the owner
        // can call addVerifier with the tombstone address.
        if (verifiers[selector] == UNSET) {
            revert SelectorUnknown({selector: selector});
        }
        verifiers[selector] = TOMBSTONE;
    }

    /// @notice Get the associated verifier, reverting if the selector is unknown or removed.
    function getVerifier(bytes4 selector) public view returns (IRiscZeroVerifier) {
        IRiscZeroVerifier verifier = verifiers[selector];
        if (verifier == UNSET) {
            revert SelectorUnknown({selector: selector});
        }
        if (verifier == TOMBSTONE) {
            revert SelectorRemoved({selector: selector});
        }
        return verifier;
    }

    /// @notice Get the associated verifier, reverting if the selector is unknown or removed.
    function getVerifier(bytes calldata seal) public view returns (IRiscZeroVerifier) {
        // Use the first 4 bytes of the seal at the selector to look up in the mapping.
        return getVerifier(bytes4(seal[0:4]));
    }

    /// @inheritdoc IRiscZeroVerifier
    function verify(bytes calldata seal, bytes32 imageId, bytes32 journalDigest) external view {
        getVerifier(seal).verify(seal, imageId, journalDigest);
    }

    /// @inheritdoc IRiscZeroVerifier
    function verifyIntegrity(Receipt calldata receipt) external view {
        getVerifier(receipt.seal).verifyIntegrity(receipt);
    }
}

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

/// @title IForwarder
/// @author Anoma Foundation, 2025
/// @notice The interface for forwarder contracts that can be called from the protocol adapter and allow the resource
/// machine to interoperate with external EVM state.
/// @custom:security-contact [email protected]
interface IForwarder {
    /// @notice Forwards an external call to read or write EVM state. This function can only be called by the
    /// protocol adapter contract.
    /// @param  logicRef The resource logic hash.
    /// @param input The `bytes` encoded calldata (including the `bytes4` function selector).
    /// @return output The `bytes` encoded output of the call.
    function forwardCall(bytes32 logicRef, bytes memory input) external returns (bytes memory output);
}

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

import {Transaction} from "../Types.sol";

/// @title IProtocolAdapter
/// @author Anoma Foundation, 2025
/// @notice The interface of the protocol adapter contract verifying and executing resource machine transactions.
/// @custom:security-contact [email protected]
interface IProtocolAdapter {
    /// @notice Emitted when a transaction is executed.
    /// @param tags The tags of resources being consumed and created in this transaction in alternating order.
    /// @param logicRefs The logic references of resources being consumed and created in this transaction.
    event TransactionExecuted(bytes32[] tags, bytes32[] logicRefs);

    /// @notice Emitted when an action is executed.
    /// @param actionTreeRoot The action tree root.
    /// @param actionTagCount The number of tags in the action.
    event ActionExecuted(bytes32 actionTreeRoot, uint256 actionTagCount);

    /// @notice Emitted when a forwarder call is executed.
    /// @param untrustedForwarder The forwarder contract forwarding the call.
    /// @param input The input data for the forwarded call.
    /// @param output The expected output data from the forwarded call.
    event ForwarderCallExecuted(address indexed untrustedForwarder, bytes input, bytes output);

    /// @notice Emitted to store a resource payload blob persistently.
    /// @param tag The tag of the resource this blob belongs to.
    /// @param index The index of the blob in the payload array.
    /// @param blob The blob.
    event ResourcePayload(bytes32 indexed tag, uint256 index, bytes blob);

    /// @notice Emitted to store a discovery payload blob persistently.
    /// @param tag The tag of the resource this blob belongs to.
    /// @param index The index of the blob in the payload array.
    /// @param blob The blob.
    event DiscoveryPayload(bytes32 indexed tag, uint256 index, bytes blob);

    /// @notice Emitted to store a external payload blob persistently.
    /// @param tag The tag of the resource this blob belongs to.
    /// @param index The index of the blob in the payload array.
    /// @param blob The blob.
    event ExternalPayload(bytes32 indexed tag, uint256 index, bytes blob);

    /// @notice Emitted to store an application payload blob persistently.
    /// @param tag The tag of the resource this blob belongs to.
    /// @param index The index of the blob in the payload array.
    /// @param blob The blob.
    event ApplicationPayload(bytes32 indexed tag, uint256 index, bytes blob);

    /// @notice Executes a transaction by adding the commitments and nullifiers to the commitment tree and nullifier
    /// set, respectively.
    /// @param transaction The transaction to execute.
    function execute(Transaction calldata transaction) external;

    /// @notice Simulates a transaction and returns the gas after reverting.
    /// @param transaction The transaction to simulate execution for.
    /// @param skipRiscZeroProofVerification Whether to skip RISC Zero proof verification or not.
    /// @dev This transaction will always revert.
    function simulateExecute(Transaction calldata transaction, bool skipRiscZeroProofVerification) external;

    /// @notice Stops the protocol adapter permanently in case of an emergency.
    function emergencyStop() external;

    /// @notice Returns whether the protocol adapter has been stopped or not. This can have two reasons:
    /// 1. The RISC Zero verifier associated with the protocol adapter has been stopped.
    /// 2. The protocol adapter itself was stopped by the owner.
    /// @return isStopped Whether the protocol adapter has been stopped or not.
    function isEmergencyStopped() external view returns (bool isStopped);

    /// @notice Returns the RISC Zero verifier router associated with the protocol adapter.
    /// @return verifierRouter The RISC Zero verifier router.
    function getRiscZeroVerifierRouter() external view returns (address verifierRouter);

    /// @notice Returns the RISC Zero verifier selector associated with the protocol adapter.
    /// @return verifierSelector The RISC Zero verifier selector.
    function getRiscZeroVerifierSelector() external view returns (bytes4 verifierSelector);
}

File 8 of 40 : IVersion.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

/// @title IVersion
/// @author Anoma Foundation, 2025
/// @notice The interface for versioned contracts.
/// @custom:security-contact [email protected]
interface IVersion {
    /// @notice Returns the semantic version number of the contract.
    /// @return version The semantic version number.
    function getVersion() external view returns (bytes32 version);
}

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

import {Arrays} from "@openzeppelin-contracts-5.5.0/utils/Arrays.sol";
import {Math} from "@openzeppelin-contracts-5.5.0/utils/math/Math.sol";

import {SHA256} from "../libs/SHA256.sol";

/// @title MerkleTree
/// @author Anoma Foundation, 2025
/// @notice A Merkle tree implementation populating a tree of variable depth from left to right.
/// @dev This is a modified version of the OpenZeppelin `MerkleTree` implementation
/// (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/utils/structs/MerkleTree.sol).
/// @custom:security-contact [email protected]
library MerkleTree {
    struct Tree {
        uint256 _nextLeafIndex;
        bytes32[] _sides;
        bytes32[] _zeros;
    }

    /// @notice Sets up the tree with an initial capacity (i.e. number of leaves) of 1
    /// and returns the initial root of the empty tree.
    /// @param self The tree data structure.
    /// @return initialRoot The initial root of the empty tree.
    function setup(Tree storage self) internal returns (bytes32 initialRoot) {
        initialRoot = SHA256.EMPTY_HASH;

        // Store depth in the dynamic array
        Arrays.unsafeSetLength(self._zeros, 256);

        // Build each root of zero-filled subtrees
        bytes32 currentZero = SHA256.EMPTY_HASH;
        for (uint256 i = 0; i < 256; ++i) {
            Arrays.unsafeAccess(self._zeros, i).value = currentZero;
            currentZero = SHA256.hash(currentZero, currentZero);
        }

        self._nextLeafIndex = 0;
    }

    /// @notice Pushes a leaf to the tree.
    /// @param self The tree data structure.
    /// @param leaf The leaf to add.
    /// @return index The index of the leaf.
    /// @return newRoot The new root of the tree.
    function push(Tree storage self, bytes32 leaf) internal returns (uint256 index, bytes32 newRoot) {
        // Cache the tree depth read.
        uint256 treeDepth = depth(self);

        // Get the next leaf index and increment it after assignment.
        index = self._nextLeafIndex++;

        // Rebuild the branch from leaf to root.
        uint256 currentIndex = index;
        bytes32 currentLevelHash = leaf;
        for (uint256 i = 0; i < treeDepth; ++i) {
            // Compute the next level hash for depth `i+1`.
            // Check whether the `currentIndex` node is the left or right child of its parent.
            if (isLeftChild(currentIndex)) {
                // Store the current hash as the sibling (side) for the current level.
                Arrays.unsafeAccess(self._sides, i).value = currentLevelHash;

                // Compute the current level hash using the right sibling, which is the zero hash of this level.
                currentLevelHash = SHA256.hash(currentLevelHash, Arrays.unsafeAccess(self._zeros, i).value);
            } else {
                // Compute the current level hash using the left sibling (side).
                currentLevelHash = SHA256.hash(Arrays.unsafeAccess(self._sides, i).value, currentLevelHash);
            }

            currentIndex >>= 1;
        }

        // Expand the tree if the capacity is reached.
        if (self._nextLeafIndex == capacity(self)) {
            // Store the current level hash as the sibling (side) for the current level.
            self._sides.push(currentLevelHash);

            // Compute the new current level hash.
            currentLevelHash = SHA256.hash(currentLevelHash, Arrays.unsafeAccess(self._zeros, treeDepth).value);
        }

        newRoot = currentLevelHash;
    }

    /// @notice Returns the tree depth.
    /// @param self The tree data structure.
    /// @return treeDepth The depth of the tree.
    function depth(Tree storage self) internal view returns (uint8 treeDepth) {
        treeDepth = uint8(self._sides.length);
    }

    /// @notice Returns the number of leaves that have been added to the tree.
    /// @param self The tree data structure.
    /// @return count The number of leaves in the tree.
    function leafCount(Tree storage self) internal view returns (uint256 count) {
        count = self._nextLeafIndex;
    }

    /// @notice Calculates the capacity of the tree.
    /// @param self The tree data structure.
    /// @return treeCapacity The computed tree capacity.
    function capacity(Tree storage self) internal view returns (uint256 treeCapacity) {
        treeCapacity = uint256(1) << depth(self); // 2^treeDepth
    }

    /// @notice Checks whether a node is the left or right child according to its index.
    /// @param index The index to check.
    /// @return isLeft Whether this node is the left or right child.
    function isLeftChild(uint256 index) internal pure returns (bool isLeft) {
        isLeft = (index & 1) == 0;
    }

    /// @notice Computes the root of a Merkle tree.
    /// @param leaves The leaves of the tree.
    /// @param treeDepth The depth of the tree.
    /// @return root The computed root.
    /// @dev This method should only be used for trees with low depth.
    function computeRoot(bytes32[] memory leaves, uint8 treeDepth) internal pure returns (bytes32 root) {
        uint256 treeCapacity = uint256(1) << treeDepth; // 2^treeDepth

        // Create array of full leaf set with padding if necessary
        bytes32[] memory nodes = new bytes32[](treeCapacity);
        for (uint256 i = 0; i < treeCapacity; ++i) {
            if (i < leaves.length) {
                nodes[i] = leaves[i];
            } else {
                nodes[i] = SHA256.EMPTY_HASH;
            }
        }

        // Build the tree upward
        uint256 currentLevelCapacity = treeCapacity;
        while (currentLevelCapacity > 1) {
            currentLevelCapacity /= 2;

            for (uint256 i = 0; i < currentLevelCapacity; ++i) {
                nodes[i] = SHA256.hash(nodes[2 * i], nodes[2 * i + 1]);
            }
        }

        root = nodes[0];
    }

    /// @notice Computes the root of a Merkle tree using the minimal tree depth to fit all leaves.
    /// @param leaves The leaves of the tree.
    /// @return root The computed root.
    /// @dev This method should only be used for trees with low depth.
    function computeRoot(bytes32[] memory leaves) internal pure returns (bytes32 root) {
        root = MerkleTree.computeRoot({leaves: leaves, treeDepth: computeMinimalTreeDepth(leaves.length)});
    }

    /// @notice Computes the minimal required tree depth for a number of leaves.
    /// @param leavesCount The number of leaves.
    /// @return treeDepth The minimal required tree depth.
    function computeMinimalTreeDepth(uint256 leavesCount) internal pure returns (uint8 treeDepth) {
        treeDepth = uint8(Math.log2({value: leavesCount, rounding: Math.Rounding.Ceil}));
    }
}

File 10 of 40 : Aggregation.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

import {Compliance} from "./Compliance.sol";
import {Logic} from "./Logic.sol";

/// @title Aggregation
/// @author Anoma Foundation, 2025
/// @notice A library containing type definitions of the aggregation proving system.
/// @custom:security-contact [email protected]
library Aggregation {
    /// @notice An instance struct containing aggregated instances of all resources and compliance
    /// units in a given transaction.
    /// @param logicRefs The logic references of all resources in a transaction.
    /// @param complianceInstances The aggregated compliance instances of a transaction.
    /// @param logicInstances The instances for checking logic proofs in a transaction.
    struct Instance {
        bytes32[] logicRefs;
        Compliance.Instance[] complianceInstances;
        Logic.Instance[] logicInstances;
    }

    /// @notice The aggregation verifying key.
    /// @dev The key is fixed as long as the aggregation circuit binary is not changed.
    bytes32 internal constant _VERIFYING_KEY = 0x213b3f40d7c113c1a012072fcd791fa44bf5166a2300121630bd3228e2b00827;
}

File 11 of 40 : Compliance.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

/// @title Compliance
/// @author Anoma Foundation, 2025
/// @notice A library containing type definitions and verifying key of the compliance proving system.
/// @custom:security-contact [email protected]
library Compliance {
    /// @notice The compliance instance containing the data required to verify the compliance unit being constituted by
    /// one consumed and one created resource.
    /// @param consumed References associated with the consumed resource in the compliance unit.
    /// @param created References associated with the created resource in the compliance unit.
    /// @param unitDeltaX The x-coordinate of the delta value of this unit.
    /// @param unitDeltaY The y-coordinate of the delta value of this unit.
    struct Instance {
        ConsumedRefs consumed;
        CreatedRefs created;
        bytes32 unitDeltaX;
        bytes32 unitDeltaY;
    }

    /// @notice A struct containing references associated with the consumed resource of the compliance unit.
    /// @param nullifier The nullifier associated with the resource.
    /// @param logicRef A reference to the logic function associated with the consumed resource.
    /// @param commitmentTreeRoot The root of the commitment tree from which this resource is derived.
    struct ConsumedRefs {
        bytes32 nullifier;
        bytes32 logicRef;
        bytes32 commitmentTreeRoot;
    }

    /// @notice A struct containing references associated with the created resource of the compliance unit.
    /// @param commitment The commitment associated with the resource.
    /// @param logicRef The reference to the logic function associated with the created resource.
    struct CreatedRefs {
        bytes32 commitment;
        bytes32 logicRef;
    }

    /// @notice A struct containing all information required to verify a compliance unit.
    /// @param proof The compliance proof.
    /// @param instance The instance to the compliance proof.
    /// @dev Since the verifying key (i.e., the compliance circuit ID) is fixed, it is hardcoded below.
    struct VerifierInput {
        bytes proof;
        Instance instance;
    }

    /// @notice The number of resources contained in a compliance unit.
    uint256 internal constant _RESOURCES_PER_COMPLIANCE_UNIT = 2;

    /// @notice The compliance verifying key.
    /// @dev The key is fixed as long as the compliance circuit binary is not changed.
    /// The compliance circuit should ensure that the created resources use the consumed resource's nullifier as nonce.
    bytes32 internal constant _VERIFYING_KEY = 0x919e13001cd3319be5a5a7cb189203be083674acb3fff23d05aae9c3ed86314d;
}

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

import {ECDSA} from "@openzeppelin-contracts-5.5.0/utils/cryptography/ECDSA.sol";
import {EllipticCurve} from "elliptic-curve-solidity-0.2.5/contracts/EllipticCurve.sol";
import {EfficientHashLib} from "solady-0.1.26/src/utils/EfficientHashLib.sol";

/// @title Delta
/// @author Anoma Foundation, 2025
/// @notice A library containing methods of the delta proving system.
/// @custom:security-contact [email protected]
library Delta {
    using Delta for Point;

    /// @notice An elliptic curve point representing a delta value.
    /// @param x The x component of the point.
    /// @param y The y component of the point.
    struct Point {
        uint256 x;
        uint256 y;
    }

    /// @notice The x-coordinate of the curve generator point.
    uint256 internal constant _GX = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798;

    /// @notice The y-coordinate of the curve generator point.
    uint256 internal constant _GY = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8;

    // @notice The coefficient a of th secp256k1 (K-256) elliptic curve (y² = x³ + ax + b).
    uint256 internal constant _AA = 0;

    // @notice The coefficient b of th secp256k1 (K-256) elliptic curve (y² = x³ + ax + b).
    uint256 internal constant _BB = 7;

    /// @notice The field prime modulus (2^256 - 2^32 - 977) of the secp256k1 (K-256) elliptic curve (y² = x³ + ax + b).
    uint256 internal constant _PP = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F;

    /// @notice Thrown if the recovered delta public key doesn't match the delta instance.
    error DeltaMismatch(address expected, address actual);

    /// @notice Thrown when a provided point is not on the curve.
    error PointNotOnCurve(Point point);

    /// @notice Returns the elliptic curve point representing the zero delta.
    /// @return zeroDelta The zero delta.
    function zero() internal pure returns (Point memory zeroDelta) {
        zeroDelta = Point({x: 0, y: 0});
    }

    /// @notice Adds two delta points and returns the sum.
    /// @param lhs The left-hand side point that can also be the zero delta.
    /// @param rhs The right-hand side point that must be a curve point.
    /// @return sum The resulting curve point.
    /// @dev Note that only the right-hand side point is checked to allow adding the zero delta from the left. This is
    /// done due to the delta points being added sequentially starting from the zero delta in the
    /// `ProtocolAdapter.execute()` function.
    function add(Point memory lhs, Point memory rhs) internal pure returns (Point memory sum) {
        if (!EllipticCurve.isOnCurve({_x: rhs.x, _y: rhs.y, _aa: _AA, _bb: _BB, _pp: _PP})) {
            revert PointNotOnCurve(rhs);
        }

        (sum.x, sum.y) = EllipticCurve.ecAdd({_x1: lhs.x, _y1: lhs.y, _x2: rhs.x, _y2: rhs.y, _aa: _AA, _pp: _PP});
    }

    /// @notice Converts an elliptic curve point to an Ethereum account address.
    /// @param delta The elliptic curve point.
    /// @return account The associated account.
    function toAccount(Point memory delta) internal pure returns (address account) {
        // Hash the public key with Keccak-256.
        bytes32 hashedKey = EfficientHashLib.hash(delta.x, delta.y);

        // Take the last 20 bytes to obtain an Ethereum address.
        account = address(uint160(uint256(hashedKey)));
    }

    /// @notice Computes the delta verifying key as the Keccak-256 hash of all nullifiers and commitments
    /// as ordered in the compliance units.
    /// @param tags The list of nullifiers and commitments to compute the verifying key from.
    /// @return verifyingKey The verifying key obtained from hashing the nullifiers and commitments.
    function computeVerifyingKey(bytes32[] memory tags) internal pure returns (bytes32 verifyingKey) {
        verifyingKey = EfficientHashLib.hash(tags);
    }

    /// @notice Verifies a delta proof.
    /// @param proof The delta proof.
    /// @param instance The transaction delta.
    /// @param verifyingKey The Keccak-256 hash of all nullifiers and commitments as ordered in the compliance units.
    function verify(bytes memory proof, Point memory instance, bytes32 verifyingKey) internal pure {
        // Verify the delta proof using the ECDSA.recover API to obtain the address
        address recovered = ECDSA.recover({hash: verifyingKey, signature: proof});

        // Convert the public key to an address
        address expected = toAccount(instance);

        // Compare it with the recovered address
        if (recovered != expected) {
            revert DeltaMismatch({expected: expected, actual: recovered});
        }
    }
}

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

/// @title Logic
/// @author Anoma Foundation, 2025
/// @notice A library containing type definitions and methods of the logic proving system.
/// @custom:security-contact [email protected]
library Logic {
    /// @notice An enum representing the supported blob deletion criteria.
    enum DeletionCriterion {
        Immediately,
        Never
    }

    /// @notice A struct containing information required to verify a logic proof.
    /// @param tag The nullifier or commitment of the resource depending on if the resource is consumed or not.
    /// @param verifyingKey The logic verifying key (i.e., the hash of the logic function).
    /// @param appData The application data associated with the resource.
    /// @param proof The logic proof.
    struct VerifierInput {
        bytes32 tag;
        bytes32 verifyingKey;
        AppData appData;
        bytes proof;
    }

    /// @notice The logic instance containing the data required to verify a resource logic proof.
    /// @param tag The nullifier or commitment of the resource depending on whether the resource is consumed or not.
    /// @param isConsumed Whether the resource is consumed or not.
    /// @param actionTreeRoot The root of the tree containing all resources present in an action.
    /// @param appData The application data associated with the resource.
    struct Instance {
        bytes32 tag;
        bool isConsumed;
        bytes32 actionTreeRoot;
        AppData appData;
    }

    /// @notice A struct containing payloads of different kinds.
    /// @param resourcePayload A list of blobs for encoding plaintext info connected to resources.
    /// @param discoveryPayload A list of blobs for encoding data with public keys for discovery.
    /// @param externalPayload A list of blobs for encoding data connected with external calls.
    /// @param applicationPayload A list of blobs for application-specific purposes.
    struct AppData {
        ExpirableBlob[] resourcePayload;
        ExpirableBlob[] discoveryPayload;
        ExpirableBlob[] externalPayload;
        ExpirableBlob[] applicationPayload;
    }

    /// @notice A blob with a deletion criterion attached.
    /// @param deletionCriterion The deletion criterion.
    /// @param blob The bytes-encoded blob data.
    struct ExpirableBlob {
        DeletionCriterion deletionCriterion;
        bytes blob;
    }

    /// @notice Thrown if a tag is not found in a list of verifier inputs.
    error TagNotFound(bytes32 tag);

    /// @notice Returns a logic instance given a logic verifier input, an action tree root, and depending on whether
    /// associated resource is consumed or not.
    /// @param input The logic verifier input to construct the instance from.
    /// @param actionTreeRoot The action tree root to put into the instance.
    /// @param isConsumed Whether the associated resource is consumed or not.
    /// @return instance The resulting instance.
    function toInstance(Logic.VerifierInput memory input, bytes32 actionTreeRoot, bool isConsumed)
        internal
        pure
        returns (Instance memory instance)
    {
        instance = Instance({
            tag: input.tag, isConsumed: isConsumed, actionTreeRoot: actionTreeRoot, appData: input.appData
        });
    }

    /// @notice Looks up a `VerifierInput` element from a list by its tag.
    /// @param list The list of verifier inputs.
    /// @param tag The tag to look up.
    /// @return foundElement The found `VerifierInput` element.
    function lookup(VerifierInput[] calldata list, bytes32 tag)
        internal
        pure
        returns (VerifierInput calldata foundElement)
    {
        uint256 len = list.length;
        for (uint256 i = 0; i < len; ++i) {
            if (list[i].tag == tag) {
                return foundElement = list[i];
            }
        }
        revert TagNotFound(tag);
    }
}

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

import {reverseByteOrderUint32} from "risc0-risc0-ethereum-3.0.1/contracts/src/Util.sol";

import {Aggregation} from "./proving/Aggregation.sol";
import {Compliance} from "./proving/Compliance.sol";
import {Logic} from "./proving/Logic.sol";

/// @title RiscZeroUtils
/// @author Anoma Foundation, 2025
/// @notice A library containing utility functions to encode resource machine types to the RISC Zero journal format.
/// @custom:security-contact [email protected]
library RiscZeroUtils {
    using RiscZeroUtils for Compliance.Instance;
    using RiscZeroUtils for Logic.Instance;

    /// @notice Converts the compliance instance to the RISC Zero journal format.
    /// @param instance The compliance instance.
    /// @return journal The resulting RISC Zero journal.
    function toJournal(Compliance.Instance memory instance) internal pure returns (bytes memory journal) {
        journal = abi.encodePacked(
            instance.consumed.nullifier,
            instance.consumed.logicRef,
            instance.consumed.commitmentTreeRoot,
            instance.created.commitment,
            instance.created.logicRef,
            instance.unitDeltaX,
            instance.unitDeltaY
        );
    }

    /// @notice Converts the logic instance to the RISC Zero journal format.
    /// @param input The logic verifier input.
    /// @return converted The converted journal.
    /// @dev Blob counts / payload lengths can safely be assumed to not exceed the `type(uint32).max` as this would
    /// exceed Ethereum's block gas limit. Note that safe-math is still applied.
    function toJournal(Logic.Instance memory input) internal pure returns (bytes memory converted) {
        Logic.AppData memory appData = input.appData;

        // slither-disable-start too-many-digits
        uint32 risc0BoolTrueLittleEndian = 0x01000000;
        uint32 risc0BoolFalseLittleEndian = 0x00000000;
        // slither-disable-end too-many-digits

        converted = abi.encodePacked(
            input.tag,
            // Encode the `isConsumed` boolean as a `uint32` in reverse (little-endian) byte order.
            input.isConsumed ? risc0BoolTrueLittleEndian : risc0BoolFalseLittleEndian,
            input.actionTreeRoot,
            //
            // Encode the resource payload length as a `uint32` in reverse byte order.
            reverseByteOrderUint32(uint32(appData.resourcePayload.length)),
            encodePayload(appData.resourcePayload),
            //
            // Encode the discovery payload length as a `uint32` in reverse byte order.
            reverseByteOrderUint32(uint32(appData.discoveryPayload.length)),
            encodePayload(appData.discoveryPayload),
            //
            // Encode the external payload length as a `uint32` in reverse byte order.
            reverseByteOrderUint32(uint32(appData.externalPayload.length)),
            encodePayload(appData.externalPayload),
            //
            // Encode the application payload length as a `uint32` in reverse byte order.
            reverseByteOrderUint32(uint32(appData.applicationPayload.length)),
            encodePayload(appData.applicationPayload)
        );
    }

    /// @notice Converts the aggregation instance to the RISC Zero journal format.
    /// @param instance The aggregation instance.
    /// @return journal The resulting RISC Zero journal.
    /// @dev Payload, blob, and journal lengths (divided by 4) can safely be assumed to not exceed the
    /// `type(uint32).max` as this would exceed Ethereum's block gas limit.
    function toJournal(Aggregation.Instance memory instance) internal pure returns (bytes memory journal) {
        uint256 complianceUnitCount = instance.complianceInstances.length;

        bytes memory packedComplianceJournals = "";
        bytes memory packedLogicJournals = "";

        for (uint256 i = 0; i < complianceUnitCount; ++i) {
            // Pack the compliance instance journals.
            packedComplianceJournals =
                abi.encodePacked(packedComplianceJournals, instance.complianceInstances[i].toJournal());

            // Pack the logic instance journals.
            {
                bytes memory consumedJournal =
                    instance.logicInstances[(i * Compliance._RESOURCES_PER_COMPLIANCE_UNIT)].toJournal();
                bytes memory createdJournal =
                    instance.logicInstances[(i * Compliance._RESOURCES_PER_COMPLIANCE_UNIT) + 1].toJournal();

                packedLogicJournals = abi.encodePacked(
                    packedLogicJournals,
                    // Encode the created journal length (which is a multiple of `32 bytes`) divided by 4 (bytes)
                    // representing the number of RISC Zero words in reverse (little-endian) byte order.
                    // forge-lint: disable-next-line(unsafe-typecast)
                    reverseByteOrderUint32(uint32(consumedJournal.length / 4)),
                    consumedJournal,
                    // Encode the consumed journal length (which is a multiple of `32 bytes`) divided by 4 (bytes)
                    // representing the number of RISC Zero words in reverse (little-endian) byte order.
                    // forge-lint: disable-next-line(unsafe-typecast)
                    reverseByteOrderUint32(uint32(createdJournal.length / 4)),
                    createdJournal
                );
            }
        }

        // Encode the compliance unit and tag count as a `uint32` in reverse (little-endian) byte order.
        // forge-lint: disable-next-line(unsafe-typecast)
        uint32 complianceUnitCountPadding = reverseByteOrderUint32(uint32(complianceUnitCount));

        uint32 tagCountPadding =
        // forge-lint: disable-next-line(unsafe-typecast)
        reverseByteOrderUint32(uint32(complianceUnitCount * Compliance._RESOURCES_PER_COMPLIANCE_UNIT));

        // Pack the aggregation instance journal.
        journal = abi.encodePacked(
            // Add the padded compliance journals.
            complianceUnitCountPadding,
            packedComplianceJournals,
            //
            // Add the compliance verifying key.
            Compliance._VERIFYING_KEY,
            //
            // Add the tag count-padded logic journals.
            tagCountPadding,
            packedLogicJournals,
            //
            // Add the tag count-padded logic references.
            tagCountPadding,
            instance.logicRefs
        );
    }

    /// @notice Encodes a payload to the RISC Zero journal format.
    /// @param payload The payload.
    /// @return encoded The encoded bytes of the payload.
    /// @dev The blob length divided by 4 can safely be assumed to not exceed the `type(uint32).max` as this
    /// would exceed Ethereum's block gas limit.
    function encodePayload(Logic.ExpirableBlob[] memory payload) internal pure returns (bytes memory encoded) {
        uint256 blobCount = payload.length;
        for (uint256 i = 0; i < blobCount; ++i) {
            encoded = abi.encodePacked(
                encoded,
                // Encode the blob length (which is a multiple of `32 bytes`) divided by 4 (bytes) representing the
                // number of RISC Zero words in reverse (little-endian) byte order.
                reverseByteOrderUint32(uint32(payload[i].blob.length / 4)),
                payload[i].blob,
                // Encode the blob deletion criterion as a `uint32` in reverse (little-endian) byte order.
                reverseByteOrderUint32(uint32(payload[i].deletionCriterion))
            );
        }
    }
}

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

import {Transaction, Action} from "../Types.sol";
import {Compliance} from "./proving/Compliance.sol";

/// @title TagUtils
/// @author Anoma Foundation, 2025
/// @notice A library containing utility functions to collect and count tags.
/// @custom:security-contact [email protected]
library TagUtils {
    using TagUtils for Action;

    error TagCountMismatch(uint256 expected, uint256 actual);

    /// @notice Collects the resource tags in an action as ordered by the compliance units.
    /// @param action The action to collect the tags from.
    /// @return tags The collected tags.
    function collectTags(Action calldata action) internal pure returns (bytes32[] memory tags) {
        uint256 complianceUnitCount = action.complianceVerifierInputs.length;

        tags = new bytes32[](complianceUnitCount * Compliance._RESOURCES_PER_COMPLIANCE_UNIT);

        for (uint256 i = 0; i < complianceUnitCount; ++i) {
            Compliance.Instance calldata instance = action.complianceVerifierInputs[i].instance;
            uint256 index = i * Compliance._RESOURCES_PER_COMPLIANCE_UNIT;
            tags[index] = instance.consumed.nullifier;
            tags[index + 1] = instance.created.commitment;
        }
    }

    /// @notice Counts the resource tags in a transaction and checks for each action that the tag count within is
    /// twice the number of compliance units.
    /// @param transaction The transaction to count and check the tags for.
    /// @return tagCount The computed tag count.
    function countTags(Transaction calldata transaction) internal pure returns (uint256 tagCount) {
        uint256 actionCount = transaction.actions.length;

        // Count the total number of tags in the transaction.
        for (uint256 i = 0; i < actionCount; ++i) {
            tagCount += transaction.actions[i].checkedActionTagCount();
        }
    }

    /// @notice Checks and returns the action tag count that must be twice the number of compliance units.
    /// @param action The action to check and return the tag count for.
    /// @return actionTagCount The checked action tag count.
    function checkedActionTagCount(Action calldata action) internal pure returns (uint256 actionTagCount) {
        uint256 complianceUnitCount = action.complianceVerifierInputs.length;
        actionTagCount = action.logicVerifierInputs.length;

        // Check that the tag count in the action and compliance units matches.
        if (actionTagCount != complianceUnitCount * Compliance._RESOURCES_PER_COMPLIANCE_UNIT) {
            revert TagCountMismatch({
                expected: actionTagCount, actual: complianceUnitCount * Compliance._RESOURCES_PER_COMPLIANCE_UNIT
            });
        }
    }
}

File 16 of 40 : Versioning.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

/// @title Versioning
/// @author Anoma Foundation, 2025
/// @notice A library containing constants relevant to the protocol adapter versioning.
/// @custom:security-contact [email protected]
library Versioning {
    /// @notice The semantic version number of the Anoma protocol adapter.
    bytes32 internal constant _PROTOCOL_ADAPTER_VERSION = "1.1.0";

    /// @notice The RISC Zero verifier selector that the protocol adapter is associated with.
    bytes4 internal constant _RISC_ZERO_VERIFIER_SELECTOR = 0x73c457ba;
}

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

import {EnumerableSet} from "@openzeppelin-contracts-5.5.0/utils/structs/EnumerableSet.sol";

import {ICommitmentTree} from "../interfaces/ICommitmentTree.sol";
import {MerkleTree} from "../libs/MerkleTree.sol";

/// @title CommitmentTree
/// @author Anoma Foundation, 2025
/// @notice A commitment tree being inherited by the protocol adapter.
/// @dev The contract is based on a modified version of OZ's `MerkleTree` implementation and and the unchanged OZ
/// `EnumerableSet` implementation.
/// @custom:security-contact [email protected]
contract CommitmentTree is ICommitmentTree {
    using MerkleTree for MerkleTree.Tree;
    using EnumerableSet for EnumerableSet.Bytes32Set;

    MerkleTree.Tree internal _merkleTree;
    EnumerableSet.Bytes32Set internal _roots;

    error NonExistingRoot(bytes32 root);
    error PreExistingRoot(bytes32 root);

    /// @notice Initializes the commitment accumulator by setting up a Merkle tree.
    constructor() {
        bytes32 initialRoot = _merkleTree.setup();

        // slither-disable-next-line unused-return
        _roots.add(initialRoot);

        emit CommitmentTreeRootAdded({root: initialRoot});
    }

    /// @inheritdoc ICommitmentTree
    function commitmentCount() external view override returns (uint256 count) {
        count = _merkleTree.leafCount();
    }

    /// @inheritdoc ICommitmentTree
    function commitmentTreeDepth() external view override returns (uint8 depth) {
        depth = _merkleTree.depth();
    }

    /// @inheritdoc ICommitmentTree
    function commitmentTreeCapacity() external view override returns (uint256 capacity) {
        capacity = _merkleTree.capacity();
    }

    /// @inheritdoc ICommitmentTree
    function isCommitmentTreeRootContained(bytes32 root) external view override returns (bool isContained) {
        isContained = _isCommitmentTreeRootContained(root);
    }

    /// @inheritdoc ICommitmentTree
    function commitmentTreeRootCount() external view override returns (uint256 count) {
        count = _roots.length();
    }

    /// @inheritdoc ICommitmentTree
    function commitmentTreeRootAtIndex(uint256 index) external view override returns (bytes32 root) {
        root = _roots.at(index);
    }

    /// @inheritdoc ICommitmentTree
    function latestCommitmentTreeRoot() external view override returns (bytes32 root) {
        root = _roots.at(_roots.length() - 1);
    }

    /// @notice Adds a commitment to the accumulator and returns the new root.
    /// @param commitment The commitment to add.
    /// @return newRoot The resulting new root.
    function _addCommitment(bytes32 commitment) internal returns (bytes32 newRoot) {
        uint256 index;
        (index, newRoot) = _merkleTree.push(commitment);
    }

    /// @notice Adds a root to the set of historical roots and emits the `CommitmentTreeRootAdded` event.
    /// @param root The root to store.
    function _addCommitmentTreeRoot(bytes32 root) internal {
        if (!_roots.add(root)) {
            revert PreExistingRoot(root);
        }
        emit CommitmentTreeRootAdded(root);
    }

    /// @notice Checks if a commitment tree root is contained in the set of historical roots.
    /// @param root The root to check.
    /// @return isContained Whether the root exists or not.
    function _isCommitmentTreeRootContained(bytes32 root) internal view returns (bool isContained) {
        isContained = _roots.contains(root);
    }
}

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

import {EnumerableSet} from "@openzeppelin-contracts-5.5.0/utils/structs/EnumerableSet.sol";

import {INullifierSet} from "../interfaces/INullifierSet.sol";

/// @title NullifierSet
/// @author Anoma Foundation, 2025
/// @notice A nullifier set being inherited by the protocol adapter.
/// @dev The implementation is based on OpenZeppelin's `EnumerableSet` implementation.
/// @custom:security-contact [email protected]
contract NullifierSet is INullifierSet {
    using EnumerableSet for EnumerableSet.Bytes32Set;

    /// @notice The nullifier set data structure.
    EnumerableSet.Bytes32Set internal _nullifierSet;

    error PreExistingNullifier(bytes32 nullifier);

    /// @inheritdoc INullifierSet
    function isNullifierContained(bytes32 nullifier) external view override returns (bool isContained) {
        isContained = _nullifierSet.contains(nullifier);
    }

    /// @inheritdoc INullifierSet
    function nullifierCount() external view override returns (uint256 count) {
        count = _nullifierSet.length();
    }

    /// @inheritdoc INullifierSet
    function nullifierAtIndex(uint256 index) external view override returns (bytes32 nullifier) {
        nullifier = _nullifierSet.at(index);
    }

    /// @notice Adds a nullifier to the set, if it does not exist already.
    /// @param nullifier The nullifier to add.
    function _addNullifier(bytes32 nullifier) internal {
        (bool success) = _nullifierSet.add(nullifier);
        if (!success) {
            revert PreExistingNullifier(nullifier);
        }
    }
}

File 19 of 40 : Types.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

import {Compliance} from "./libs/proving/Compliance.sol";
import {Logic} from "./libs/proving/Logic.sol";

/// @notice The resource object constituting the atomic unit of state in the Anoma protocol.
/// @param  logicRef The hash of the resource logic function.
/// @param  labelRef The hash of the resource label, which can contain arbitrary data.
/// @param  valueRef The hash of the resource value, which can contain arbitrary data.
/// @param  nullifierKeyCommitment The commitment to the nullifier key.
/// @param  quantity The quantity that the resource represents.
/// @param  nonce The nonce guaranteeing the resource's uniqueness.
/// @param  randSeed The randomness seed that can be used to derive pseudo-randomness for applications.
/// @param  ephemeral The resource's ephemerality.
struct Resource {
    bytes32 logicRef;
    bytes32 labelRef;
    bytes32 valueRef;
    bytes32 nullifierKeyCommitment;
    bytes32 nonce;
    bytes32 randSeed;
    uint128 quantity;
    bool ephemeral;
}

/// @notice The transaction object containing all required data to conduct a RM state transition
/// in which resources get consumed and created.
/// @param actions The list of actions to be executed.
/// @param deltaProof The proof for the transaction delta value.
/// @param aggregationProof A recursive proof of all compliance and resource logics in the transaction.
struct Transaction {
    Action[] actions;
    bytes deltaProof;
    bytes aggregationProof;
}

/// @notice The action object providing context separation between non-intersecting sets of resources.
/// @param logicVerifierInputs The logic inputs of each resource consumed or created in the action.
/// @param complianceVerifierInputs The compliance units comprising one consumed and one created resource, each.
struct Action {
    Logic.VerifierInput[] logicVerifierInputs;
    Compliance.VerifierInput[] complianceVerifierInputs;
}

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

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

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

pragma solidity ^0.8.24;

/**
 * @dev Library for reading and writing value-types to specific transient storage slots.
 *
 * Transient slots are often used to store temporary values that are removed after the current transaction.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 *  * Example reading and writing values using transient storage:
 * ```solidity
 * contract Lock {
 *     using TransientSlot for *;
 *
 *     // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
 *     bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542;
 *
 *     modifier locked() {
 *         require(!_LOCK_SLOT.asBoolean().tload());
 *
 *         _LOCK_SLOT.asBoolean().tstore(true);
 *         _;
 *         _LOCK_SLOT.asBoolean().tstore(false);
 *     }
 * }
 * ```
 *
 * TIP: Consider using this library along with {SlotDerivation}.
 */
library TransientSlot {
    /**
     * @dev UDVT that represents a slot holding an address.
     */
    type AddressSlot is bytes32;

    /**
     * @dev Cast an arbitrary slot to a AddressSlot.
     */
    function asAddress(bytes32 slot) internal pure returns (AddressSlot) {
        return AddressSlot.wrap(slot);
    }

    /**
     * @dev UDVT that represents a slot holding a bool.
     */
    type BooleanSlot is bytes32;

    /**
     * @dev Cast an arbitrary slot to a BooleanSlot.
     */
    function asBoolean(bytes32 slot) internal pure returns (BooleanSlot) {
        return BooleanSlot.wrap(slot);
    }

    /**
     * @dev UDVT that represents a slot holding a bytes32.
     */
    type Bytes32Slot is bytes32;

    /**
     * @dev Cast an arbitrary slot to a Bytes32Slot.
     */
    function asBytes32(bytes32 slot) internal pure returns (Bytes32Slot) {
        return Bytes32Slot.wrap(slot);
    }

    /**
     * @dev UDVT that represents a slot holding a uint256.
     */
    type Uint256Slot is bytes32;

    /**
     * @dev Cast an arbitrary slot to a Uint256Slot.
     */
    function asUint256(bytes32 slot) internal pure returns (Uint256Slot) {
        return Uint256Slot.wrap(slot);
    }

    /**
     * @dev UDVT that represents a slot holding a int256.
     */
    type Int256Slot is bytes32;

    /**
     * @dev Cast an arbitrary slot to a Int256Slot.
     */
    function asInt256(bytes32 slot) internal pure returns (Int256Slot) {
        return Int256Slot.wrap(slot);
    }

    /**
     * @dev Load the value held at location `slot` in transient storage.
     */
    function tload(AddressSlot slot) internal view returns (address value) {
        assembly ("memory-safe") {
            value := tload(slot)
        }
    }

    /**
     * @dev Store `value` at location `slot` in transient storage.
     */
    function tstore(AddressSlot slot, address value) internal {
        assembly ("memory-safe") {
            tstore(slot, value)
        }
    }

    /**
     * @dev Load the value held at location `slot` in transient storage.
     */
    function tload(BooleanSlot slot) internal view returns (bool value) {
        assembly ("memory-safe") {
            value := tload(slot)
        }
    }

    /**
     * @dev Store `value` at location `slot` in transient storage.
     */
    function tstore(BooleanSlot slot, bool value) internal {
        assembly ("memory-safe") {
            tstore(slot, value)
        }
    }

    /**
     * @dev Load the value held at location `slot` in transient storage.
     */
    function tload(Bytes32Slot slot) internal view returns (bytes32 value) {
        assembly ("memory-safe") {
            value := tload(slot)
        }
    }

    /**
     * @dev Store `value` at location `slot` in transient storage.
     */
    function tstore(Bytes32Slot slot, bytes32 value) internal {
        assembly ("memory-safe") {
            tstore(slot, value)
        }
    }

    /**
     * @dev Load the value held at location `slot` in transient storage.
     */
    function tload(Uint256Slot slot) internal view returns (uint256 value) {
        assembly ("memory-safe") {
            value := tload(slot)
        }
    }

    /**
     * @dev Store `value` at location `slot` in transient storage.
     */
    function tstore(Uint256Slot slot, uint256 value) internal {
        assembly ("memory-safe") {
            tstore(slot, value)
        }
    }

    /**
     * @dev Load the value held at location `slot` in transient storage.
     */
    function tload(Int256Slot slot) internal view returns (int256 value) {
        assembly ("memory-safe") {
            value := tload(slot)
        }
    }

    /**
     * @dev Store `value` at location `slot` in transient storage.
     */
    function tstore(Int256Slot slot, int256 value) internal {
        assembly ("memory-safe") {
            tstore(slot, value)
        }
    }
}

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

pragma solidity ^0.8.20;

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

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * This extension of the {Ownable} contract includes a two-step mechanism to transfer
 * ownership, where the new owner must call {acceptOwnership} in order to replace the
 * old one. This can help prevent common mistakes, such as transfers of ownership to
 * incorrect accounts, or to contracts that are unable to interact with the
 * permission system.
 *
 * The initial owner is specified at deployment time in the constructor for `Ownable`. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2Step is Ownable {
    address private _pendingOwner;

    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        return _pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     *
     * Setting `newOwner` to the zero address is allowed; this can be used to cancel an initiated ownership transfer.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        _pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        delete _pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        if (pendingOwner() != sender) {
            revert OwnableUnauthorizedAccount(sender);
        }
        _transferOwnership(sender);
    }
}

// Copyright 2025 RISC Zero, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.9;

import {reverseByteOrderUint32} from "./Util.sol";

/// @notice A receipt attesting to a claim using the RISC Zero proof system.
/// @dev A receipt contains two parts: a seal and a claim.
///
/// The seal is a zero-knowledge proof attesting to knowledge of a witness for the claim. The claim
/// is a set of public outputs, and for zkVM execution is the hash of a `ReceiptClaim` struct.
///
/// IMPORTANT: The `claimDigest` field must be a hash computed by the caller for verification to
/// have meaningful guarantees. Treat this similar to verifying an ECDSA signature, in that hashing
/// is a key operation in verification. The most common way to calculate this hash is to use the
/// `ReceiptClaimLib.ok(imageId, journalDigest).digest()` for successful executions.
struct Receipt {
    bytes seal;
    bytes32 claimDigest;
}

/// @notice Public claims about a zkVM guest execution, such as the journal committed to by the guest.
/// @dev Also includes important information such as the exit code and the starting and ending system
/// state (i.e. the state of memory). `ReceiptClaim` is a "Merkle-ized struct" supporting
/// partial openings of the underlying fields from a hash commitment to the full structure.
struct ReceiptClaim {
    /// @notice Digest of the SystemState just before execution has begun.
    bytes32 preStateDigest;
    /// @notice Digest of the SystemState just after execution has completed.
    bytes32 postStateDigest;
    /// @notice The exit code for the execution.
    ExitCode exitCode;
    /// @notice A digest of the input to the guest.
    /// @dev This field is currently unused and must be set to the zero digest.
    bytes32 input;
    /// @notice Digest of the Output of the guest, including the journal
    /// and assumptions set during execution.
    bytes32 output;
}

library ReceiptClaimLib {
    using OutputLib for Output;
    using SystemStateLib for SystemState;

    bytes32 constant TAG_DIGEST = sha256("risc0.ReceiptClaim");

    // Define a constant to ensure hashing is done at compile time. Can't use the
    // SystemStateLib.digest method here because the Solidity compiler complains.
    bytes32 constant SYSTEM_STATE_ZERO_DIGEST = 0xa3acc27117418996340b84e5a90f3ef4c49d22c79e44aad822ec9c313e1eb8e2;

    /// @notice Construct a ReceiptClaim from the given imageId and journalDigest.
    ///         Returned ReceiptClaim will represent a successful execution of the zkVM, running
    ///         the program committed by imageId and resulting in the journal specified by
    ///         journalDigest.
    /// @param imageId The identifier for the guest program.
    /// @param journalDigest The SHA-256 digest of the journal bytes.
    /// @dev Input hash and postStateDigest are set to all-zeros (i.e. no committed input, or
    ///      final memory state), the exit code is (Halted, 0), and there are no assumptions
    ///      (i.e. the receipt is unconditional).
    function ok(bytes32 imageId, bytes32 journalDigest) internal pure returns (ReceiptClaim memory) {
        return ReceiptClaim(
            imageId,
            SYSTEM_STATE_ZERO_DIGEST,
            ExitCode(SystemExitCode.Halted, 0),
            bytes32(0),
            Output(journalDigest, bytes32(0)).digest()
        );
    }

    function digest(ReceiptClaim memory claim) internal pure returns (bytes32) {
        return sha256(
            abi.encodePacked(
                TAG_DIGEST,
                // down
                claim.input,
                claim.preStateDigest,
                claim.postStateDigest,
                claim.output,
                // data
                uint32(claim.exitCode.system) << 24,
                uint32(claim.exitCode.user) << 24,
                // down.length
                uint16(4) << 8
            )
        );
    }
}

/// @notice Commitment to the memory state and program counter (pc) of the zkVM.
/// @dev The "pre" and "post" fields of the ReceiptClaim are digests of the system state at the
///      start are stop of execution. Programs are loaded into the zkVM by creating a memory image
///      of the loaded program, and creating a system state for initializing the zkVM. This is
///      known as the "image ID".
struct SystemState {
    /// @notice Program counter.
    uint32 pc;
    /// @notice Root hash of a merkle tree which confirms the integrity of the memory image.
    bytes32 merkle_root;
}

library SystemStateLib {
    bytes32 constant TAG_DIGEST = sha256("risc0.SystemState");

    function digest(SystemState memory state) internal pure returns (bytes32) {
        return sha256(
            abi.encodePacked(
                TAG_DIGEST,
                // down
                state.merkle_root,
                // data
                reverseByteOrderUint32(state.pc),
                // down.length
                uint16(1) << 8
            )
        );
    }
}

/// @notice Exit condition indicated by the zkVM at the end of the guest execution.
/// @dev Exit codes have a "system" part and a "user" part. Semantically, the system part is set to
/// indicate the type of exit (e.g. halt, pause, or system split) and is directly controlled by the
/// zkVM. The user part is an exit code, similar to exit codes used in Linux, chosen by the guest
/// program to indicate additional information (e.g. 0 to indicate success or 1 to indicate an
/// error).
struct ExitCode {
    SystemExitCode system;
    uint8 user;
}

/// @notice Exit condition indicated by the zkVM at the end of the execution covered by this proof.
/// @dev
/// `Halted` indicates normal termination of a program with an interior exit code returned from the
/// guest program. A halted program cannot be resumed.
///
/// `Paused` indicates the execution ended in a paused state with an interior exit code set by the
/// guest program. A paused program can be resumed such that execution picks up where it left
/// of, with the same memory state.
///
/// `SystemSplit` indicates the execution ended on a host-initiated system split. System split is
/// mechanism by which the host can temporarily stop execution of the execution ended in a system
/// split has no output and no conclusions can be drawn about whether the program will eventually
/// halt. System split is used in continuations to split execution into individually provable segments.
enum SystemExitCode {
    Halted,
    Paused,
    SystemSplit
}

/// @notice Output field in the `ReceiptClaim`, committing to a claimed journal and assumptions list.
struct Output {
    /// @notice Digest of the journal committed to by the guest execution.
    bytes32 journalDigest;
    /// @notice Digest of the ordered list of `ReceiptClaim` digests corresponding to the
    /// calls to `env::verify` and `env::verify_integrity`.
    /// @dev Verifying the integrity of a `Receipt` corresponding to a `ReceiptClaim` with a
    /// non-empty assumptions list does not guarantee unconditionally any of the claims over the
    /// guest execution (i.e. if the assumptions list is non-empty, then the journal digest cannot
    /// be trusted to correspond to a genuine execution). The claims can be checked by additional
    /// verifying a `Receipt` for every digest in the assumptions list.
    bytes32 assumptionsDigest;
}

library OutputLib {
    bytes32 constant TAG_DIGEST = sha256("risc0.Output");

    function digest(Output memory output) internal pure returns (bytes32) {
        return sha256(
            abi.encodePacked(
                TAG_DIGEST,
                // down
                output.journalDigest,
                output.assumptionsDigest,
                // down.length
                uint16(2) << 8
            )
        );
    }
}

/// @notice Error raised when cryptographic verification of the zero-knowledge proof fails.
error VerificationFailed();

/// @notice Verifier interface for RISC Zero receipts of execution.
interface IRiscZeroVerifier {
    /// @notice Verify that the given seal is a valid RISC Zero proof of execution with the
    ///     given image ID and journal digest. Reverts on failure.
    /// @dev This method additionally ensures that the input hash is all-zeros (i.e. no
    /// committed input), the exit code is (Halted, 0), and there are no assumptions (i.e. the
    /// receipt is unconditional).
    /// @param seal The encoded cryptographic proof (i.e. SNARK).
    /// @param imageId The identifier for the guest program.
    /// @param journalDigest The SHA-256 digest of the journal bytes.
    function verify(bytes calldata seal, bytes32 imageId, bytes32 journalDigest) external view;

    /// @notice Verify that the given receipt is a valid RISC Zero receipt, ensuring the `seal` is
    /// valid a cryptographic proof of the execution with the given `claim`. Reverts on failure.
    /// @param receipt The receipt to be verified.
    function verifyIntegrity(Receipt calldata receipt) external view;
}

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

pragma solidity ^0.8.24;

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 Copies the content of `array`, from `start` (included) to the end of `array` into a new address array in
     * memory.
     *
     * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`]
     */
    function slice(address[] memory array, uint256 start) internal pure returns (address[] memory) {
        return slice(array, start, array.length);
    }

    /**
     * @dev Copies the content of `array`, from `start` (included) to `end` (excluded) into a new address array in
     * memory. The `end` argument is truncated to the length of the `array`.
     *
     * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`]
     */
    function slice(address[] memory array, uint256 start, uint256 end) internal pure returns (address[] memory) {
        // sanitize
        end = Math.min(end, array.length);
        start = Math.min(start, end);

        // allocate and copy
        address[] memory result = new address[](end - start);
        assembly ("memory-safe") {
            mcopy(add(result, 0x20), add(add(array, 0x20), mul(start, 0x20)), mul(sub(end, start), 0x20))
        }

        return result;
    }

    /**
     * @dev Copies the content of `array`, from `start` (included) to the end of `array` into a new bytes32 array in
     * memory.
     *
     * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`]
     */
    function slice(bytes32[] memory array, uint256 start) internal pure returns (bytes32[] memory) {
        return slice(array, start, array.length);
    }

    /**
     * @dev Copies the content of `array`, from `start` (included) to `end` (excluded) into a new bytes32 array in
     * memory. The `end` argument is truncated to the length of the `array`.
     *
     * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`]
     */
    function slice(bytes32[] memory array, uint256 start, uint256 end) internal pure returns (bytes32[] memory) {
        // sanitize
        end = Math.min(end, array.length);
        start = Math.min(start, end);

        // allocate and copy
        bytes32[] memory result = new bytes32[](end - start);
        assembly ("memory-safe") {
            mcopy(add(result, 0x20), add(add(array, 0x20), mul(start, 0x20)), mul(sub(end, start), 0x20))
        }

        return result;
    }

    /**
     * @dev Copies the content of `array`, from `start` (included) to the end of `array` into a new uint256 array in
     * memory.
     *
     * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`]
     */
    function slice(uint256[] memory array, uint256 start) internal pure returns (uint256[] memory) {
        return slice(array, start, array.length);
    }

    /**
     * @dev Copies the content of `array`, from `start` (included) to `end` (excluded) into a new uint256 array in
     * memory. The `end` argument is truncated to the length of the `array`.
     *
     * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`]
     */
    function slice(uint256[] memory array, uint256 start, uint256 end) internal pure returns (uint256[] memory) {
        // sanitize
        end = Math.min(end, array.length);
        start = Math.min(start, end);

        // allocate and copy
        uint256[] memory result = new uint256[](end - start);
        assembly ("memory-safe") {
            mcopy(add(result, 0x20), add(add(array, 0x20), mul(start, 0x20)), mul(sub(end, start), 0x20))
        }

        return result;
    }

    /**
     * @dev Moves the content of `array`, from `start` (included) to the end of `array` to the start of that array.
     *
     * NOTE: This function modifies the provided array in place. If you need to preserve the original array, use {slice} instead.
     * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice[Javascript's `Array.splice`]
     */
    function splice(address[] memory array, uint256 start) internal pure returns (address[] memory) {
        return splice(array, start, array.length);
    }

    /**
     * @dev Moves the content of `array`, from `start` (included) to `end` (excluded) to the start of that array. The
     * `end` argument is truncated to the length of the `array`.
     *
     * NOTE: This function modifies the provided array in place. If you need to preserve the original array, use {slice} instead.
     * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice[Javascript's `Array.splice`]
     */
    function splice(address[] memory array, uint256 start, uint256 end) internal pure returns (address[] memory) {
        // sanitize
        end = Math.min(end, array.length);
        start = Math.min(start, end);

        // move and resize
        assembly ("memory-safe") {
            mcopy(add(array, 0x20), add(add(array, 0x20), mul(start, 0x20)), mul(sub(end, start), 0x20))
            mstore(array, sub(end, start))
        }

        return array;
    }

    /**
     * @dev Moves the content of `array`, from `start` (included) to the end of `array` to the start of that array.
     *
     * NOTE: This function modifies the provided array in place. If you need to preserve the original array, use {slice} instead.
     * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice[Javascript's `Array.splice`]
     */
    function splice(bytes32[] memory array, uint256 start) internal pure returns (bytes32[] memory) {
        return splice(array, start, array.length);
    }

    /**
     * @dev Moves the content of `array`, from `start` (included) to `end` (excluded) to the start of that array. The
     * `end` argument is truncated to the length of the `array`.
     *
     * NOTE: This function modifies the provided array in place. If you need to preserve the original array, use {slice} instead.
     * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice[Javascript's `Array.splice`]
     */
    function splice(bytes32[] memory array, uint256 start, uint256 end) internal pure returns (bytes32[] memory) {
        // sanitize
        end = Math.min(end, array.length);
        start = Math.min(start, end);

        // move and resize
        assembly ("memory-safe") {
            mcopy(add(array, 0x20), add(add(array, 0x20), mul(start, 0x20)), mul(sub(end, start), 0x20))
            mstore(array, sub(end, start))
        }

        return array;
    }

    /**
     * @dev Moves the content of `array`, from `start` (included) to the end of `array` to the start of that array.
     *
     * NOTE: This function modifies the provided array in place. If you need to preserve the original array, use {slice} instead.
     * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice[Javascript's `Array.splice`]
     */
    function splice(uint256[] memory array, uint256 start) internal pure returns (uint256[] memory) {
        return splice(array, start, array.length);
    }

    /**
     * @dev Moves the content of `array`, from `start` (included) to `end` (excluded) to the start of that array. The
     * `end` argument is truncated to the length of the `array`.
     *
     * NOTE: This function modifies the provided array in place. If you need to preserve the original array, use {slice} instead.
     * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice[Javascript's `Array.splice`]
     */
    function splice(uint256[] memory array, uint256 start, uint256 end) internal pure returns (uint256[] memory) {
        // sanitize
        end = Math.min(end, array.length);
        start = Math.min(start, end);

        // move and resize
        assembly ("memory-safe") {
            mcopy(add(array, 0x20), add(add(array, 0x20), mul(start, 0x20)), mul(sub(end, start), 0x20))
            mstore(array, sub(end, start))
        }

        return array;
    }

    /**
     * @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)
        }
    }
}

File 25 of 40 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.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 `condition ? a : b`. 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. `condition ? a : b`) 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;
    }

    /**
     * @dev Counts the number of leading zero bits in a uint256.
     */
    function clz(uint256 x) internal pure returns (uint256) {
        return ternary(x == 0, 256, 255 - log2(x));
    }
}

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

/// @title SHA256
/// @author Anoma Foundation, 2025
/// @notice A library for computing SHA256 hashes.
/// @custom:security-contact [email protected]
library SHA256 {
    /// @notice The hash of the string "EMPTY".
    /// @dev Obtained from `sha256("EMPTY")` (`0xcc1d2f838445db7aec431df9ee8a871f40e7aa5e064fc056633ef8c60fab7b06`).
    bytes32 public constant EMPTY_HASH = 0xcc1d2f838445db7aec431df9ee8a871f40e7aa5e064fc056633ef8c60fab7b06;

    /// @notice Hashes a single `bytes32` value.
    /// @param a The value to hash.
    /// @return ha The resulting hash.
    function hash(bytes32 a) internal pure returns (bytes32 ha) {
        ha = sha256(abi.encode(a));
    }

    /// @notice Hashes two `bytes32` values.
    /// @param a The first value to hash.
    /// @param b The second value to hash.
    /// @return hab The resulting hash.
    function hash(bytes32 a, bytes32 b) internal pure returns (bytes32 hab) {
        hab = sha256(abi.encode(a, b));
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.20;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS
    }

    /**
     * @dev The signature derives the `address(0)`.
     */
    error ECDSAInvalidSignature();

    /**
     * @dev The signature has an invalid length.
     */
    error ECDSAInvalidSignatureLength(uint256 length);

    /**
     * @dev The signature has an S value that is in the upper half order.
     */
    error ECDSAInvalidSignatureS(bytes32 s);

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
     * return address(0) without also returning an error description. Errors are documented using an enum (error type)
     * and a bytes32 providing additional information about the error.
     *
     * If no error is returned, then the address can be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * NOTE: This function only supports 65-byte signatures. ERC-2098 short signatures are rejected. This restriction
     * is DEPRECATED and will be removed in v6.0. Developers SHOULD NOT use signatures as unique identifiers; use hash
     * invalidation or nonces for replay protection.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     *
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     */
    function tryRecover(
        bytes32 hash,
        bytes memory signature
    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            assembly ("memory-safe") {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
        }
    }

    /**
     * @dev Variant of {tryRecover} that takes a signature in calldata
     */
    function tryRecoverCalldata(
        bytes32 hash,
        bytes calldata signature
    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, calldata slices would work here, but are
            // significantly more expensive (length check) than using calldataload in assembly.
            assembly ("memory-safe") {
                r := calldataload(signature.offset)
                s := calldataload(add(signature.offset, 0x20))
                v := byte(0, calldataload(add(signature.offset, 0x40)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * NOTE: This function only supports 65-byte signatures. ERC-2098 short signatures are rejected. This restriction
     * is DEPRECATED and will be removed in v6.0. Developers SHOULD NOT use signatures as unique identifiers; use hash
     * invalidation or nonces for replay protection.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Variant of {recover} that takes a signature in calldata
     */
    function recoverCalldata(bytes32 hash, bytes calldata signature) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecoverCalldata(hash, signature);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures]
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
        unchecked {
            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
            // We do not check for an overflow here since the shift operation results in 0 or 1.
            uint8 v = uint8((uint256(vs) >> 255) + 27);
            return tryRecover(hash, v, r, s);
        }
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS, s);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature, bytes32(0));
        }

        return (signer, RecoverError.NoError, bytes32(0));
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Parse a signature into its `v`, `r` and `s` components. Supports 65-byte and 64-byte (ERC-2098)
     * formats. Returns (0,0,0) for invalid signatures.
     *
     * For 64-byte signatures, `v` is automatically normalized to 27 or 28.
     * For 65-byte signatures, `v` is returned as-is and MUST already be 27 or 28 for use with ecrecover.
     *
     * Consider validating the result before use, or use {tryRecover}/{recover} which perform full validation.
     */
    function parse(bytes memory signature) internal pure returns (uint8 v, bytes32 r, bytes32 s) {
        assembly ("memory-safe") {
            // Check the signature length
            switch mload(signature)
            // - case 65: r,s,v signature (standard)
            case 65 {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098)
            case 64 {
                let vs := mload(add(signature, 0x40))
                r := mload(add(signature, 0x20))
                s := and(vs, shr(1, not(0)))
                v := add(shr(255, vs), 27)
            }
            default {
                r := 0
                s := 0
                v := 0
            }
        }
    }

    /**
     * @dev Variant of {parse} that takes a signature in calldata
     */
    function parseCalldata(bytes calldata signature) internal pure returns (uint8 v, bytes32 r, bytes32 s) {
        assembly ("memory-safe") {
            // Check the signature length
            switch signature.length
            // - case 65: r,s,v signature (standard)
            case 65 {
                r := calldataload(signature.offset)
                s := calldataload(add(signature.offset, 0x20))
                v := byte(0, calldataload(add(signature.offset, 0x40)))
            }
            // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098)
            case 64 {
                let vs := calldataload(add(signature.offset, 0x20))
                r := calldataload(signature.offset)
                s := and(vs, shr(1, not(0)))
                v := add(shr(255, vs), 27)
            }
            default {
                r := 0
                s := 0
                v := 0
            }
        }
    }

    /**
     * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
     */
    function _throwError(RecoverError error, bytes32 errorArg) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert ECDSAInvalidSignature();
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert ECDSAInvalidSignatureLength(uint256(errorArg));
        } else if (error == RecoverError.InvalidSignatureS) {
            revert ECDSAInvalidSignatureS(errorArg);
        }
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 ** @title Elliptic Curve Library
 ** @dev Library providing arithmetic operations over elliptic curves.
 ** This library does not check whether the inserted points belong to the curve
 ** `isOnCurve` function should be used by the library user to check the aforementioned statement.
 ** @author Witnet Foundation
 */
library EllipticCurve {
    // Pre-computed constant for 2 ** 255
    uint256 private constant U255_MAX_PLUS_1 =
        57896044618658097711785492504343953926634992332820282019728792003956564819968;

    /// @dev Modular euclidean inverse of a number (mod p).
    /// @param _x The number
    /// @param _pp The modulus
    /// @return q such that x*q = 1 (mod _pp)
    function invMod(uint256 _x, uint256 _pp) internal pure returns (uint256) {
        require(_x != 0 && _x != _pp && _pp != 0, "Invalid number");
        uint256 q = 0;
        uint256 newT = 1;
        uint256 r = _pp;
        uint256 t;
        while (_x != 0) {
            t = r / _x;
            (q, newT) = (newT, addmod(q, (_pp - mulmod(t, newT, _pp)), _pp));
            (r, _x) = (_x, r - t * _x);
        }

        return q;
    }

    /// @dev Modular exponentiation, b^e % _pp.
    /// Source: https://github.com/androlo/standard-contracts/blob/master/contracts/src/crypto/ECCMath.sol
    /// @param _base base
    /// @param _exp exponent
    /// @param _pp modulus
    /// @return r such that r = b**e (mod _pp)
    function expMod(
            uint256 _base,
            uint256 _exp,
            uint256 _pp
        )
        internal pure
        returns (uint256) 
    {
        require(_pp != 0, "EllipticCurve: modulus is zero");

        if (_base == 0) return 0;
        if (_exp == 0) return 1;

        uint256 r = 1;
        uint256 bit = U255_MAX_PLUS_1;
        assembly {
            for {

            } gt(bit, 0) {

            } {
                r := mulmod(
                    mulmod(r, r, _pp),
                    exp(_base, iszero(iszero(and(_exp, bit)))),
                    _pp
                )
                r := mulmod(
                    mulmod(r, r, _pp),
                    exp(_base, iszero(iszero(and(_exp, div(bit, 2))))),
                    _pp
                )
                r := mulmod(
                    mulmod(r, r, _pp),
                    exp(_base, iszero(iszero(and(_exp, div(bit, 4))))),
                    _pp
                )
                r := mulmod(
                    mulmod(r, r, _pp),
                    exp(_base, iszero(iszero(and(_exp, div(bit, 8))))),
                    _pp
                )
                bit := div(bit, 16)
            }
        }

        return r;
    }

    /// @dev Converts a point (x, y, z) expressed in Jacobian coordinates to affine coordinates (x', y', 1).
    /// @param _x coordinate x
    /// @param _y coordinate y
    /// @param _z coordinate z
    /// @param _pp the modulus
    /// @return (x', y') affine coordinates
    function toAffine(
            uint256 _x,
            uint256 _y,
            uint256 _z,
            uint256 _pp
        )
        internal pure 
        returns (uint256, uint256) 
    {
        uint256 zInv = invMod(_z, _pp);
        uint256 zInv2 = mulmod(zInv, zInv, _pp);
        uint256 x2 = mulmod(_x, zInv2, _pp);
        uint256 y2 = mulmod(_y, mulmod(zInv, zInv2, _pp), _pp);

        return (x2, y2);
    }

    /// @dev Derives the y coordinate from a compressed-format point x [[SEC-1]](https://www.secg.org/SEC1-Ver-1.0.pdf).
    /// @param _prefix parity byte (0x02 even, 0x03 odd)
    /// @param _x coordinate x
    /// @param _aa constant of curve
    /// @param _bb constant of curve
    /// @param _pp the modulus
    /// @return y coordinate y
    function deriveY(
            uint8 _prefix,
            uint256 _x,
            uint256 _aa,
            uint256 _bb,
            uint256 _pp
        ) 
        internal pure 
        returns (uint256) 
    {
        require(
            _prefix == 0x02 || _prefix == 0x03,
            "EllipticCurve:innvalid compressed EC point prefix"
        );

        // x^3 + ax + b
        uint256 y2 = addmod(
            mulmod(_x, mulmod(_x, _x, _pp), _pp),
            addmod(mulmod(_x, _aa, _pp), _bb, _pp),
            _pp
        );
        y2 = expMod(y2, (_pp + 1) / 4, _pp);
        // uint256 cmp = yBit ^ y_ & 1;
        uint256 y = (y2 + _prefix) % 2 == 0 ? y2 : _pp - y2;

        return y;
    }

    /// @dev Check whether point (x,y) is on curve defined by a, b, and _pp.
    /// @param _x coordinate x of P1
    /// @param _y coordinate y of P1
    /// @param _aa constant of curve
    /// @param _bb constant of curve
    /// @param _pp the modulus
    /// @return true if x,y in the curve, false else
    function isOnCurve(
            uint _x,
            uint _y,
            uint _aa,
            uint _bb,
            uint _pp
        ) 
        internal pure 
        returns (bool) 
    {
        if (0 == _x || _x >= _pp || 0 == _y || _y >= _pp) {
            return false;
        }
        // y^2
        uint lhs = mulmod(_y, _y, _pp);
        // x^3
        uint rhs = mulmod(mulmod(_x, _x, _pp), _x, _pp);
        if (_aa != 0) {
            // x^3 + a*x
            rhs = addmod(rhs, mulmod(_x, _aa, _pp), _pp);
        }
        if (_bb != 0) {
            // x^3 + a*x + b
            rhs = addmod(rhs, _bb, _pp);
        }

        return lhs == rhs;
    }

    /// @dev Calculate inverse (x, -y) of point (x, y).
    /// @param _x coordinate x of P1
    /// @param _y coordinate y of P1
    /// @param _pp the modulus
    /// @return (x, -y)
    function ecInv(
            uint256 _x,
            uint256 _y,
            uint256 _pp
        ) 
        internal pure 
        returns (uint256, uint256) 
    {
        return (_x, (_pp - _y) % _pp);
    }

    /// @dev Add two points (x1, y1) and (x2, y2) in affine coordinates.
    /// @param _x1 coordinate x of P1
    /// @param _y1 coordinate y of P1
    /// @param _x2 coordinate x of P2
    /// @param _y2 coordinate y of P2
    /// @param _aa constant of the curve
    /// @param _pp the modulus
    /// @return (qx, qy) = P1+P2 in affine coordinates
    function ecAdd(
            uint256 _x1,
            uint256 _y1,
            uint256 _x2,
            uint256 _y2,
            uint256 _aa,
            uint256 _pp
        ) 
        internal pure 
        returns (uint256, uint256) 
    {
        uint x = 0;
        uint y = 0;
        uint z = 0;

        // Double if x1==x2 else add
        if (_x1 == _x2) {
            // y1 = -y2 mod p
            if (addmod(_y1, _y2, _pp) == 0) {
                return (0, 0);
            } else {
                // P1 = P2
                (x, y, z) = jacDouble(_x1, _y1, 1, _aa, _pp);
            }
        } else {
            (x, y, z) = jacAdd(_x1, _y1, 1, _x2, _y2, 1, _pp);
        }
        // Get back to affine
        return toAffine(x, y, z, _pp);
    }

    /// @dev Substract two points (x1, y1) and (x2, y2) in affine coordinates.
    /// @param _x1 coordinate x of P1
    /// @param _y1 coordinate y of P1
    /// @param _x2 coordinate x of P2
    /// @param _y2 coordinate y of P2
    /// @param _aa constant of the curve
    /// @param _pp the modulus
    /// @return (qx, qy) = P1-P2 in affine coordinates
    function ecSub(
            uint256 _x1,
            uint256 _y1,
            uint256 _x2,
            uint256 _y2,
            uint256 _aa,
            uint256 _pp
        ) 
        internal pure 
        returns (uint256, uint256) 
    {
        // invert square
        (uint256 x, uint256 y) = ecInv(_x2, _y2, _pp);
        // P1-square
        return ecAdd(_x1, _y1, x, y, _aa, _pp);
    }

    /// @dev Multiply point (x1, y1, z1) times d in affine coordinates.
    /// @param _k scalar to multiply
    /// @param _x coordinate x of P1
    /// @param _y coordinate y of P1
    /// @param _aa constant of the curve
    /// @param _pp the modulus
    /// @return (qx, qy) = d*P in affine coordinates
    function ecMul(
            uint256 _k,
            uint256 _x,
            uint256 _y,
            uint256 _aa,
            uint256 _pp
        ) 
        internal pure 
        returns (uint256, uint256) 
    {
        // Jacobian multiplication
        (uint256 x1, uint256 y1, uint256 z1) = jacMul(_k, _x, _y, 1, _aa, _pp);
        // Get back to affine
        return toAffine(x1, y1, z1, _pp);
    }

    /// @dev Adds two points (x1, y1, z1) and (x2 y2, z2).
    /// @param _x1 coordinate x of P1
    /// @param _y1 coordinate y of P1
    /// @param _z1 coordinate z of P1
    /// @param _x2 coordinate x of square
    /// @param _y2 coordinate y of square
    /// @param _z2 coordinate z of square
    /// @param _pp the modulus
    /// @return (qx, qy, qz) P1+square in Jacobian
    function jacAdd(
            uint256 _x1,
            uint256 _y1,
            uint256 _z1,
            uint256 _x2,
            uint256 _y2,
            uint256 _z2,
            uint256 _pp
        ) 
        internal pure 
        returns (uint256, uint256, uint256) 
    {
        if (_x1 == 0 && _y1 == 0) return (_x2, _y2, _z2);
        if (_x2 == 0 && _y2 == 0) return (_x1, _y1, _z1);

        // We follow the equations described in https://pdfs.semanticscholar.org/5c64/29952e08025a9649c2b0ba32518e9a7fb5c2.pdf Section 5
        uint[4] memory zs; // z1^2, z1^3, z2^2, z2^3
        zs[0] = mulmod(_z1, _z1, _pp);
        zs[1] = mulmod(_z1, zs[0], _pp);
        zs[2] = mulmod(_z2, _z2, _pp);
        zs[3] = mulmod(_z2, zs[2], _pp);

        // u1, s1, u2, s2
        zs = [
            mulmod(_x1, zs[2], _pp),
            mulmod(_y1, zs[3], _pp),
            mulmod(_x2, zs[0], _pp),
            mulmod(_y2, zs[1], _pp)
        ];

        // In case of zs[0] == zs[2] && zs[1] == zs[3], double function should be used
        require(
            zs[0] != zs[2] || zs[1] != zs[3],
            "Use jacDouble function instead"
        );

        uint[4] memory hr;
        //h
        hr[0] = addmod(zs[2], _pp - zs[0], _pp);
        //r
        hr[1] = addmod(zs[3], _pp - zs[1], _pp);
        //h^2
        hr[2] = mulmod(hr[0], hr[0], _pp);
        // h^3
        hr[3] = mulmod(hr[2], hr[0], _pp);
        // qx = -h^3  -2u1h^2+r^2
        uint256 qx = addmod(mulmod(hr[1], hr[1], _pp), _pp - hr[3], _pp);
        qx = addmod(qx, _pp - mulmod(2, mulmod(zs[0], hr[2], _pp), _pp), _pp);
        // qy = -s1*z1*h^3+r(u1*h^2 -x^3)
        uint256 qy = mulmod(
            hr[1],
            addmod(mulmod(zs[0], hr[2], _pp), _pp - qx, _pp),
            _pp
        );
        qy = addmod(qy, _pp - mulmod(zs[1], hr[3], _pp), _pp);
        // qz = h*z1*z2
        uint256 qz = mulmod(hr[0], mulmod(_z1, _z2, _pp), _pp);
        return (qx, qy, qz);
    }

    /// @dev Doubles a points (x, y, z).
    /// @param _x coordinate x of P1
    /// @param _y coordinate y of P1
    /// @param _z coordinate z of P1
    /// @param _aa the a scalar in the curve equation
    /// @param _pp the modulus
    /// @return (qx, qy, qz) 2P in Jacobian
    function jacDouble(
            uint256 _x,
            uint256 _y,
            uint256 _z,
            uint256 _aa,
            uint256 _pp
        ) 
        internal pure 
        returns (uint256, uint256, uint256) 
    {
        if (_z == 0) return (_x, _y, _z);

        // We follow the equations described in https://pdfs.semanticscholar.org/5c64/29952e08025a9649c2b0ba32518e9a7fb5c2.pdf Section 5
        // Note: there is a bug in the paper regarding the m parameter, M=3*(x1^2)+a*(z1^4)
        // x, y, z at this point represent the squares of _x, _y, _z
        uint256 x = mulmod(_x, _x, _pp); //x1^2
        uint256 y = mulmod(_y, _y, _pp); //y1^2
        uint256 z = mulmod(_z, _z, _pp); //z1^2

        // s
        uint s = mulmod(4, mulmod(_x, y, _pp), _pp);
        // m
        uint m = addmod(
            mulmod(3, x, _pp),
            mulmod(_aa, mulmod(z, z, _pp), _pp),
            _pp
        );

        // x, y, z at this point will be reassigned and rather represent qx, qy, qz from the paper
        // This allows to reduce the gas cost and stack footprint of the algorithm
        // qx
        x = addmod(mulmod(m, m, _pp), _pp - addmod(s, s, _pp), _pp);
        // qy = -8*y1^4 + M(S-T)
        y = addmod(
            mulmod(m, addmod(s, _pp - x, _pp), _pp),
            _pp - mulmod(8, mulmod(y, y, _pp), _pp),
            _pp
        );
        // qz = 2*y1*z1
        z = mulmod(2, mulmod(_y, _z, _pp), _pp);

        return (x, y, z);
    }

    /// @dev Multiply point (x, y, z) times d.
    /// @param _d scalar to multiply
    /// @param _x coordinate x of P1
    /// @param _y coordinate y of P1
    /// @param _z coordinate z of P1
    /// @param _aa constant of curve
    /// @param _pp the modulus
    /// @return (qx, qy, qz) d*P1 in Jacobian
    function jacMul(
            uint256 _d,
            uint256 _x,
            uint256 _y,
            uint256 _z,
            uint256 _aa,
            uint256 _pp
        ) 
        internal pure 
        returns (uint256, uint256, uint256) 
    {
        // Early return in case that `_d == 0`
        if (_d == 0) {
            return (_x, _y, _z);
        }

        uint256 remaining = _d;
        uint256 qx = 0;
        uint256 qy = 0;
        uint256 qz = 1;

        // Double and add algorithm
        while (remaining != 0) {
            if ((remaining & 1) != 0) {
                (qx, qy, qz) = jacAdd(qx, qy, qz, _x, _y, _z, _pp);
            }
            remaining = remaining / 2;
            (_x, _y, _z) = jacDouble(_x, _y, _z, _aa, _pp);
        }
        return (qx, qy, qz);
    }
}

File 29 of 40 : EfficientHashLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Library for efficiently performing keccak256 hashes.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/EfficientHashLib.sol)
/// @dev To avoid stack-too-deep, you can use:
/// ```
/// bytes32[] memory buffer = EfficientHashLib.malloc(10);
/// EfficientHashLib.set(buffer, 0, value0);
/// ..
/// EfficientHashLib.set(buffer, 9, value9);
/// bytes32 finalHash = EfficientHashLib.hash(buffer);
/// ```
library EfficientHashLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*               MALLOC-LESS HASHING OPERATIONS               */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns `keccak256(abi.encode(v0))`.
    function hash(bytes32 v0) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, v0)
            result := keccak256(0x00, 0x20)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0))`.
    function hash(uint256 v0) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, v0)
            result := keccak256(0x00, 0x20)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, v1))`.
    function hash(bytes32 v0, bytes32 v1) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, v0)
            mstore(0x20, v1)
            result := keccak256(0x00, 0x40)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, v1))`.
    function hash(uint256 v0, uint256 v1) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, v0)
            mstore(0x20, v1)
            result := keccak256(0x00, 0x40)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, v1, v2))`.
    function hash(bytes32 v0, bytes32 v1, bytes32 v2) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            result := keccak256(m, 0x60)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, v1, v2))`.
    function hash(uint256 v0, uint256 v1, uint256 v2) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            result := keccak256(m, 0x60)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, v1, v2, v3))`.
    function hash(bytes32 v0, bytes32 v1, bytes32 v2, bytes32 v3)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            result := keccak256(m, 0x80)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, v1, v2, v3))`.
    function hash(uint256 v0, uint256 v1, uint256 v2, uint256 v3)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            result := keccak256(m, 0x80)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v4))`.
    function hash(bytes32 v0, bytes32 v1, bytes32 v2, bytes32 v3, bytes32 v4)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            result := keccak256(m, 0xa0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v4))`.
    function hash(uint256 v0, uint256 v1, uint256 v2, uint256 v3, uint256 v4)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            result := keccak256(m, 0xa0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v5))`.
    function hash(bytes32 v0, bytes32 v1, bytes32 v2, bytes32 v3, bytes32 v4, bytes32 v5)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            result := keccak256(m, 0xc0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v5))`.
    function hash(uint256 v0, uint256 v1, uint256 v2, uint256 v3, uint256 v4, uint256 v5)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            result := keccak256(m, 0xc0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v6))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            result := keccak256(m, 0xe0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v6))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            result := keccak256(m, 0xe0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v7))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6,
        bytes32 v7
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            result := keccak256(m, 0x100)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v7))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6,
        uint256 v7
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            result := keccak256(m, 0x100)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v8))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6,
        bytes32 v7,
        bytes32 v8
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            result := keccak256(m, 0x120)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v8))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6,
        uint256 v7,
        uint256 v8
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            result := keccak256(m, 0x120)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v9))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6,
        bytes32 v7,
        bytes32 v8,
        bytes32 v9
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            result := keccak256(m, 0x140)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v9))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6,
        uint256 v7,
        uint256 v8,
        uint256 v9
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            result := keccak256(m, 0x140)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v10))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6,
        bytes32 v7,
        bytes32 v8,
        bytes32 v9,
        bytes32 v10
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            result := keccak256(m, 0x160)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v10))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6,
        uint256 v7,
        uint256 v8,
        uint256 v9,
        uint256 v10
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            result := keccak256(m, 0x160)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v11))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6,
        bytes32 v7,
        bytes32 v8,
        bytes32 v9,
        bytes32 v10,
        bytes32 v11
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            mstore(add(m, 0x160), v11)
            result := keccak256(m, 0x180)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v11))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6,
        uint256 v7,
        uint256 v8,
        uint256 v9,
        uint256 v10,
        uint256 v11
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            mstore(add(m, 0x160), v11)
            result := keccak256(m, 0x180)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v12))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6,
        bytes32 v7,
        bytes32 v8,
        bytes32 v9,
        bytes32 v10,
        bytes32 v11,
        bytes32 v12
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            mstore(add(m, 0x160), v11)
            mstore(add(m, 0x180), v12)
            result := keccak256(m, 0x1a0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v12))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6,
        uint256 v7,
        uint256 v8,
        uint256 v9,
        uint256 v10,
        uint256 v11,
        uint256 v12
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            mstore(add(m, 0x160), v11)
            mstore(add(m, 0x180), v12)
            result := keccak256(m, 0x1a0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v13))`.
    function hash(
        bytes32 v0,
        bytes32 v1,
        bytes32 v2,
        bytes32 v3,
        bytes32 v4,
        bytes32 v5,
        bytes32 v6,
        bytes32 v7,
        bytes32 v8,
        bytes32 v9,
        bytes32 v10,
        bytes32 v11,
        bytes32 v12,
        bytes32 v13
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            mstore(add(m, 0x160), v11)
            mstore(add(m, 0x180), v12)
            mstore(add(m, 0x1a0), v13)
            result := keccak256(m, 0x1c0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(v0, .., v13))`.
    function hash(
        uint256 v0,
        uint256 v1,
        uint256 v2,
        uint256 v3,
        uint256 v4,
        uint256 v5,
        uint256 v6,
        uint256 v7,
        uint256 v8,
        uint256 v9,
        uint256 v10,
        uint256 v11,
        uint256 v12,
        uint256 v13
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, v0)
            mstore(add(m, 0x20), v1)
            mstore(add(m, 0x40), v2)
            mstore(add(m, 0x60), v3)
            mstore(add(m, 0x80), v4)
            mstore(add(m, 0xa0), v5)
            mstore(add(m, 0xc0), v6)
            mstore(add(m, 0xe0), v7)
            mstore(add(m, 0x100), v8)
            mstore(add(m, 0x120), v9)
            mstore(add(m, 0x140), v10)
            mstore(add(m, 0x160), v11)
            mstore(add(m, 0x180), v12)
            mstore(add(m, 0x1a0), v13)
            result := keccak256(m, 0x1c0)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*             BYTES32 BUFFER HASHING OPERATIONS              */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns `keccak256(abi.encode(buffer[0], .., buffer[buffer.length - 1]))`.
    function hash(bytes32[] memory buffer) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := keccak256(add(buffer, 0x20), shl(5, mload(buffer)))
        }
    }

    /// @dev Sets `buffer[i]` to `value`, without a bounds check.
    /// Returns the `buffer` for function chaining.
    function set(bytes32[] memory buffer, uint256 i, bytes32 value)
        internal
        pure
        returns (bytes32[] memory)
    {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(add(buffer, shl(5, add(1, i))), value)
        }
        return buffer;
    }

    /// @dev Sets `buffer[i]` to `value`, without a bounds check.
    /// Returns the `buffer` for function chaining.
    function set(bytes32[] memory buffer, uint256 i, uint256 value)
        internal
        pure
        returns (bytes32[] memory)
    {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(add(buffer, shl(5, add(1, i))), value)
        }
        return buffer;
    }

    /// @dev Returns `new bytes32[](n)`, without zeroing out the memory.
    function malloc(uint256 n) internal pure returns (bytes32[] memory buffer) {
        /// @solidity memory-safe-assembly
        assembly {
            buffer := mload(0x40)
            mstore(buffer, n)
            mstore(0x40, add(shl(5, add(1, n)), buffer))
        }
    }

    /// @dev Frees memory that has been allocated for `buffer`.
    /// No-op if `buffer.length` is zero, or if new memory has been allocated after `buffer`.
    function free(bytes32[] memory buffer) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(buffer)
            mstore(shl(6, lt(iszero(n), eq(add(shl(5, add(1, n)), buffer), mload(0x40)))), buffer)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      EQUALITY CHECKS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns `a == abi.decode(b, (bytes32))`.
    function eq(bytes32 a, bytes memory b) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := and(eq(0x20, mload(b)), eq(a, mload(add(b, 0x20))))
        }
    }

    /// @dev Returns `abi.decode(a, (bytes32)) == a`.
    function eq(bytes memory a, bytes32 b) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := and(eq(0x20, mload(a)), eq(b, mload(add(a, 0x20))))
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*               BYTE SLICE HASHING OPERATIONS                */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the keccak256 of the slice from `start` to `end` (exclusive).
    /// `start` and `end` are byte offsets.
    function hash(bytes memory b, uint256 start, uint256 end)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(b)
            end := xor(end, mul(xor(end, n), lt(n, end)))
            start := xor(start, mul(xor(start, n), lt(n, start)))
            result := keccak256(add(add(b, 0x20), start), mul(gt(end, start), sub(end, start)))
        }
    }

    /// @dev Returns the keccak256 of the slice from `start` to the end of the bytes.
    function hash(bytes memory b, uint256 start) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(b)
            start := xor(start, mul(xor(start, n), lt(n, start)))
            result := keccak256(add(add(b, 0x20), start), mul(gt(n, start), sub(n, start)))
        }
    }

    /// @dev Returns the keccak256 of the bytes.
    function hash(bytes memory b) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := keccak256(add(b, 0x20), mload(b))
        }
    }

    /// @dev Returns the keccak256 of the slice from `start` to `end` (exclusive).
    /// `start` and `end` are byte offsets.
    function hashCalldata(bytes calldata b, uint256 start, uint256 end)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            end := xor(end, mul(xor(end, b.length), lt(b.length, end)))
            start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
            let n := mul(gt(end, start), sub(end, start))
            calldatacopy(mload(0x40), add(b.offset, start), n)
            result := keccak256(mload(0x40), n)
        }
    }

    /// @dev Returns the keccak256 of the slice from `start` to the end of the bytes.
    function hashCalldata(bytes calldata b, uint256 start) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
            let n := mul(gt(b.length, start), sub(b.length, start))
            calldatacopy(mload(0x40), add(b.offset, start), n)
            result := keccak256(mload(0x40), n)
        }
    }

    /// @dev Returns the keccak256 of the bytes.
    function hashCalldata(bytes calldata b) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            calldatacopy(mload(0x40), b.offset, b.length)
            result := keccak256(mload(0x40), b.length)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      SHA2-256 HELPERS                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns `sha256(abi.encode(b))`. Yes, it's more efficient.
    function sha2(bytes32 b) internal view returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, b)
            result := mload(staticcall(gas(), 2, 0x00, 0x20, 0x01, 0x20))
            if iszero(returndatasize()) { invalid() }
        }
    }

    /// @dev Returns the sha256 of the slice from `start` to `end` (exclusive).
    /// `start` and `end` are byte offsets.
    function sha2(bytes memory b, uint256 start, uint256 end)
        internal
        view
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(b)
            end := xor(end, mul(xor(end, n), lt(n, end)))
            start := xor(start, mul(xor(start, n), lt(n, start)))
            // forgefmt: disable-next-item
            result := mload(staticcall(gas(), 2, add(add(b, 0x20), start),
                mul(gt(end, start), sub(end, start)), 0x01, 0x20))
            if iszero(returndatasize()) { invalid() }
        }
    }

    /// @dev Returns the sha256 of the slice from `start` to the end of the bytes.
    function sha2(bytes memory b, uint256 start) internal view returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(b)
            start := xor(start, mul(xor(start, n), lt(n, start)))
            // forgefmt: disable-next-item
            result := mload(staticcall(gas(), 2, add(add(b, 0x20), start),
                mul(gt(n, start), sub(n, start)), 0x01, 0x20))
            if iszero(returndatasize()) { invalid() }
        }
    }

    /// @dev Returns the sha256 of the bytes.
    function sha2(bytes memory b) internal view returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(staticcall(gas(), 2, add(b, 0x20), mload(b), 0x01, 0x20))
            if iszero(returndatasize()) { invalid() }
        }
    }

    /// @dev Returns the sha256 of the slice from `start` to `end` (exclusive).
    /// `start` and `end` are byte offsets.
    function sha2Calldata(bytes calldata b, uint256 start, uint256 end)
        internal
        view
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            end := xor(end, mul(xor(end, b.length), lt(b.length, end)))
            start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
            let n := mul(gt(end, start), sub(end, start))
            calldatacopy(mload(0x40), add(b.offset, start), n)
            result := mload(staticcall(gas(), 2, mload(0x40), n, 0x01, 0x20))
            if iszero(returndatasize()) { invalid() }
        }
    }

    /// @dev Returns the sha256 of the slice from `start` to the end of the bytes.
    function sha2Calldata(bytes calldata b, uint256 start) internal view returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            start := xor(start, mul(xor(start, b.length), lt(b.length, start)))
            let n := mul(gt(b.length, start), sub(b.length, start))
            calldatacopy(mload(0x40), add(b.offset, start), n)
            result := mload(staticcall(gas(), 2, mload(0x40), n, 0x01, 0x20))
            if iszero(returndatasize()) { invalid() }
        }
    }

    /// @dev Returns the sha256 of the bytes.
    function sha2Calldata(bytes calldata b) internal view returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            calldatacopy(mload(0x40), b.offset, b.length)
            result := mload(staticcall(gas(), 2, mload(0x40), b.length, 0x01, 0x20))
            if iszero(returndatasize()) { invalid() }
        }
    }
}

File 30 of 40 : Util.sol
// Copyright 2024 RISC Zero, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.9;

/// @notice reverse the byte order of the uint256 value.
/// @dev Solidity uses a big-endian ABI encoding. Reversing the byte order before encoding
/// ensure that the encoded value will be little-endian.
/// Written by k06a. https://ethereum.stackexchange.com/a/83627
function reverseByteOrderUint256(uint256 input) pure returns (uint256 v) {
    v = input;

    // swap bytes
    v = ((v & 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >> 8)
        | ((v & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << 8);

    // swap 2-byte long pairs
    v = ((v & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> 16)
        | ((v & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << 16);

    // swap 4-byte long pairs
    v = ((v & 0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >> 32)
        | ((v & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << 32);

    // swap 8-byte long pairs
    v = ((v & 0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >> 64)
        | ((v & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << 64);

    // swap 16-byte long pairs
    v = (v >> 128) | (v << 128);
}

/// @notice reverse the byte order of the uint32 value.
/// @dev Solidity uses a big-endian ABI encoding. Reversing the byte order before encoding
/// ensure that the encoded value will be little-endian.
/// Written by k06a. https://ethereum.stackexchange.com/a/83627
function reverseByteOrderUint32(uint32 input) pure returns (uint32 v) {
    v = input;

    // swap bytes
    v = ((v & 0xFF00FF00) >> 8) | ((v & 0x00FF00FF) << 8);

    // swap 2-byte long pairs
    v = (v >> 16) | (v << 16);
}

/// @notice reverse the byte order of the uint16 value.
/// @dev Solidity uses a big-endian ABI encoding. Reversing the byte order before encoding
/// ensure that the encoded value will be little-endian.
/// Written by k06a. https://ethereum.stackexchange.com/a/83627
function reverseByteOrderUint16(uint16 input) pure returns (uint16 v) {
    v = input;

    // swap bytes
    v = (v >> 8) | ((v & 0x00FF) << 8);
}

File 31 of 40 : EnumerableSet.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.24;

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

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 * - Set can be cleared (all elements removed) in O(n).
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * The following types are supported:
 *
 * - `bytes32` (`Bytes32Set`) since v3.3.0
 * - `address` (`AddressSet`) since v3.3.0
 * - `uint256` (`UintSet`) since v3.3.0
 * - `string` (`StringSet`) since v5.4.0
 * - `bytes` (`BytesSet`) since v5.4.0
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position is the index of the value in the `values` array plus 1.
        // Position 0 is used to mean a value is not in the set.
        mapping(bytes32 value => uint256) _positions;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._positions[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We cache the value's position to prevent multiple reads from the same storage slot
        uint256 position = set._positions[value];

        if (position != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 valueIndex = position - 1;
            uint256 lastIndex = set._values.length - 1;

            if (valueIndex != lastIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the lastValue to the index where the value to delete is
                set._values[valueIndex] = lastValue;
                // Update the tracked position of the lastValue (that was just moved)
                set._positions[lastValue] = position;
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the tracked position for the deleted slot
            delete set._positions[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes all the values from a set. O(n).
     *
     * WARNING: This function has an unbounded cost that scales with set size. Developers should keep in mind that
     * using it may render the function uncallable if the set grows to the point where clearing it consumes too much
     * gas to fit in a block.
     */
    function _clear(Set storage set) private {
        uint256 len = _length(set);
        for (uint256 i = 0; i < len; ++i) {
            delete set._positions[set._values[i]];
        }
        Arrays.unsafeSetLength(set._values, 0);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._positions[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    /**
     * @dev Return a slice of the set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set, uint256 start, uint256 end) private view returns (bytes32[] memory) {
        unchecked {
            end = Math.min(end, _length(set));
            start = Math.min(start, end);

            uint256 len = end - start;
            bytes32[] memory result = new bytes32[](len);
            for (uint256 i = 0; i < len; ++i) {
                result[i] = Arrays.unsafeAccess(set._values, start + i).value;
            }
            return result;
        }
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Removes all the values from a set. O(n).
     *
     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
     * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
     */
    function clear(Bytes32Set storage set) internal {
        _clear(set._inner);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    /**
     * @dev Return a slice of the set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set, uint256 start, uint256 end) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner, start, end);
        bytes32[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes all the values from a set. O(n).
     *
     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
     * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
     */
    function clear(AddressSet storage set) internal {
        _clear(set._inner);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    /**
     * @dev Return a slice of the set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set, uint256 start, uint256 end) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner, start, end);
        address[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Removes all the values from a set. O(n).
     *
     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
     * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
     */
    function clear(UintSet storage set) internal {
        _clear(set._inner);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    /**
     * @dev Return a slice of the set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set, uint256 start, uint256 end) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner, start, end);
        uint256[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    struct StringSet {
        // Storage of set values
        string[] _values;
        // Position is the index of the value in the `values` array plus 1.
        // Position 0 is used to mean a value is not in the set.
        mapping(string value => uint256) _positions;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(StringSet storage set, string memory value) internal returns (bool) {
        if (!contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._positions[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(StringSet storage set, string memory value) internal returns (bool) {
        // We cache the value's position to prevent multiple reads from the same storage slot
        uint256 position = set._positions[value];

        if (position != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 valueIndex = position - 1;
            uint256 lastIndex = set._values.length - 1;

            if (valueIndex != lastIndex) {
                string memory lastValue = set._values[lastIndex];

                // Move the lastValue to the index where the value to delete is
                set._values[valueIndex] = lastValue;
                // Update the tracked position of the lastValue (that was just moved)
                set._positions[lastValue] = position;
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the tracked position for the deleted slot
            delete set._positions[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes all the values from a set. O(n).
     *
     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
     * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
     */
    function clear(StringSet storage set) internal {
        uint256 len = length(set);
        for (uint256 i = 0; i < len; ++i) {
            delete set._positions[set._values[i]];
        }
        Arrays.unsafeSetLength(set._values, 0);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(StringSet storage set, string memory value) internal view returns (bool) {
        return set._positions[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(StringSet storage set) internal view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(StringSet storage set, uint256 index) internal view returns (string memory) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(StringSet storage set) internal view returns (string[] memory) {
        return set._values;
    }

    /**
     * @dev Return a slice of the set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(StringSet storage set, uint256 start, uint256 end) internal view returns (string[] memory) {
        unchecked {
            end = Math.min(end, length(set));
            start = Math.min(start, end);

            uint256 len = end - start;
            string[] memory result = new string[](len);
            for (uint256 i = 0; i < len; ++i) {
                result[i] = Arrays.unsafeAccess(set._values, start + i).value;
            }
            return result;
        }
    }

    struct BytesSet {
        // Storage of set values
        bytes[] _values;
        // Position is the index of the value in the `values` array plus 1.
        // Position 0 is used to mean a value is not in the set.
        mapping(bytes value => uint256) _positions;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(BytesSet storage set, bytes memory value) internal returns (bool) {
        if (!contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._positions[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(BytesSet storage set, bytes memory value) internal returns (bool) {
        // We cache the value's position to prevent multiple reads from the same storage slot
        uint256 position = set._positions[value];

        if (position != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 valueIndex = position - 1;
            uint256 lastIndex = set._values.length - 1;

            if (valueIndex != lastIndex) {
                bytes memory lastValue = set._values[lastIndex];

                // Move the lastValue to the index where the value to delete is
                set._values[valueIndex] = lastValue;
                // Update the tracked position of the lastValue (that was just moved)
                set._positions[lastValue] = position;
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the tracked position for the deleted slot
            delete set._positions[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes all the values from a set. O(n).
     *
     * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
     * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
     */
    function clear(BytesSet storage set) internal {
        uint256 len = length(set);
        for (uint256 i = 0; i < len; ++i) {
            delete set._positions[set._values[i]];
        }
        Arrays.unsafeSetLength(set._values, 0);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(BytesSet storage set, bytes memory value) internal view returns (bool) {
        return set._positions[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(BytesSet storage set) internal view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(BytesSet storage set, uint256 index) internal view returns (bytes memory) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(BytesSet storage set) internal view returns (bytes[] memory) {
        return set._values;
    }

    /**
     * @dev Return a slice of the set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(BytesSet storage set, uint256 start, uint256 end) internal view returns (bytes[] memory) {
        unchecked {
            end = Math.min(end, length(set));
            start = Math.min(start, end);

            uint256 len = end - start;
            bytes[] memory result = new bytes[](len);
            for (uint256 i = 0; i < len; ++i) {
                result[i] = Arrays.unsafeAccess(set._values, start + i).value;
            }
            return result;
        }
    }
}

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

/// @title ICommitmentTree
/// @author Anoma Foundation, 2025
/// @notice The interface of the commitment tree contract.
/// @custom:security-contact [email protected]
interface ICommitmentTree {
    /// @notice Emitted when a commitment tree root is added to the set of historical roots.
    /// @param root The commitment tree root being stored.
    event CommitmentTreeRootAdded(bytes32 root);

    /// @notice Returns the number of commitments that have been added to the tree.
    /// @return count The number of commitments in the tree.
    function commitmentCount() external view returns (uint256 count);

    /// @notice Returns the commitment tree depth.
    /// @return depth The depth of the tree.
    function commitmentTreeDepth() external view returns (uint8 depth);

    /// @notice Computes the capacity of the tree based on the current tree depth.
    /// @return capacity The computed tree capacity.
    function commitmentTreeCapacity() external view returns (uint256 capacity);

    /// @notice Returns the latest  commitment tree root.
    /// @return root The latest commitment tree root.
    function latestCommitmentTreeRoot() external view returns (bytes32 root);

    /// @notice Returns whether a commitment tree root is contained in the set of historical roots or not.
    /// @param root The root to check.
    /// @return isContained Whether the root exists or not.
    function isCommitmentTreeRootContained(bytes32 root) external view returns (bool isContained);

    /// @notice Returns the number of commitment roots in the historical root set.
    /// @return count The number of commitment roots in the set.
    function commitmentTreeRootCount() external view returns (uint256 count);

    /// @notice Returns the historical commitment tree root with the given index.
    /// @param index The index to return the commitment tree root for.
    /// @return root The root at the given index.
    function commitmentTreeRootAtIndex(uint256 index) external view returns (bytes32 root);
}

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

/// @title INullifierSet
/// @author Anoma Foundation, 2025
/// @notice The interface of the nullifier set contract.
/// @custom:security-contact [email protected]
interface INullifierSet {
    /// @notice Returns whether the set contains a given nullifier or not.
    /// @param nullifier The nullifier to check.
    /// @return isContained Whether the nullifier is contained or not.
    function isNullifierContained(bytes32 nullifier) external view returns (bool isContained);

    /// @notice Returns the number of nullifiers in the nullifier set.
    /// @return count The number of nullifiers in the set.
    function nullifierCount() external view returns (uint256 count);

    /// @notice Returns the nullifier with the given index.
    /// @param index The index to return the nullifier for.
    /// @return nullifier The nullifier at the given index.
    function nullifierAtIndex(uint256 index) external view returns (bytes32 nullifier);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// 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.5.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 *;
 *
 *     // 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
        }
    }
}

// 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)
        }
    }
}

File 39 of 40 : 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.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

Settings
{
  "remappings": [
    "@openzeppelin-contracts-5.5.0/=dependencies/@openzeppelin-contracts-5.5.0/",
    "elliptic-curve-solidity-0.2.5/=dependencies/elliptic-curve-solidity-0.2.5/",
    "forge-std-1.14.0/=dependencies/forge-std-1.14.0/",
    "openzeppelin/contracts/=dependencies/risc0-risc0-ethereum-3.0.1/lib/openzeppelin-contracts/contracts/",
    "risc0-risc0-ethereum-3.0.1/=dependencies/risc0-risc0-ethereum-3.0.1/",
    "solady-0.1.26/=dependencies/solady-0.1.26/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 10000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": false
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "osaka",
  "viaIR": true
}

Contract ABI

API
[{"inputs":[{"internalType":"contract RiscZeroVerifierRouter","name":"riscZeroVerifierRouter","type":"address"},{"internalType":"bytes4","name":"riscZeroVerifierSelector","type":"bytes4"},{"internalType":"address","name":"emergencyStopCaller","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"expected","type":"address"},{"internalType":"address","name":"actual","type":"address"}],"name":"DeltaMismatch","type":"error"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[{"internalType":"bytes","name":"expected","type":"bytes"},{"internalType":"bytes","name":"actual","type":"bytes"}],"name":"ForwarderCallOutputMismatch","type":"error"},{"inputs":[{"internalType":"bytes32","name":"expected","type":"bytes32"},{"internalType":"bytes32","name":"actual","type":"bytes32"}],"name":"LogicRefMismatch","type":"error"},{"inputs":[{"internalType":"bytes32","name":"root","type":"bytes32"}],"name":"NonExistingRoot","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct Delta.Point","name":"point","type":"tuple"}],"name":"PointNotOnCurve","type":"error"},{"inputs":[{"internalType":"bytes32","name":"nullifier","type":"bytes32"}],"name":"PreExistingNullifier","type":"error"},{"inputs":[{"internalType":"bytes32","name":"root","type":"bytes32"}],"name":"PreExistingRoot","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"bytes4","name":"expected","type":"bytes4"},{"internalType":"bytes4","name":"actual","type":"bytes4"}],"name":"RiscZeroVerifierSelectorMismatch","type":"error"},{"inputs":[],"name":"RiscZeroVerifierStopped","type":"error"},{"inputs":[{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"name":"Simulated","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"TagCountMismatch","type":"error"},{"inputs":[{"internalType":"bytes32","name":"tag","type":"bytes32"}],"name":"TagNotFound","type":"error"},{"inputs":[],"name":"ZeroNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"actionTreeRoot","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"actionTagCount","type":"uint256"}],"name":"ActionExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"tag","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"blob","type":"bytes"}],"name":"ApplicationPayload","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"root","type":"bytes32"}],"name":"CommitmentTreeRootAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"tag","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"blob","type":"bytes"}],"name":"DiscoveryPayload","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"tag","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"blob","type":"bytes"}],"name":"ExternalPayload","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"untrustedForwarder","type":"address"},{"indexed":false,"internalType":"bytes","name":"input","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"output","type":"bytes"}],"name":"ForwarderCallExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"tag","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"blob","type":"bytes"}],"name":"ResourcePayload","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32[]","name":"tags","type":"bytes32[]"},{"indexed":false,"internalType":"bytes32[]","name":"logicRefs","type":"bytes32[]"}],"name":"TransactionExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"commitmentCount","outputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"commitmentTreeCapacity","outputs":[{"internalType":"uint256","name":"capacity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"commitmentTreeDepth","outputs":[{"internalType":"uint8","name":"depth","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"commitmentTreeRootAtIndex","outputs":[{"internalType":"bytes32","name":"root","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"commitmentTreeRootCount","outputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergencyStop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"components":[{"internalType":"bytes32","name":"tag","type":"bytes32"},{"internalType":"bytes32","name":"verifyingKey","type":"bytes32"},{"components":[{"components":[{"internalType":"enum Logic.DeletionCriterion","name":"deletionCriterion","type":"uint8"},{"internalType":"bytes","name":"blob","type":"bytes"}],"internalType":"struct Logic.ExpirableBlob[]","name":"resourcePayload","type":"tuple[]"},{"components":[{"internalType":"enum Logic.DeletionCriterion","name":"deletionCriterion","type":"uint8"},{"internalType":"bytes","name":"blob","type":"bytes"}],"internalType":"struct Logic.ExpirableBlob[]","name":"discoveryPayload","type":"tuple[]"},{"components":[{"internalType":"enum Logic.DeletionCriterion","name":"deletionCriterion","type":"uint8"},{"internalType":"bytes","name":"blob","type":"bytes"}],"internalType":"struct Logic.ExpirableBlob[]","name":"externalPayload","type":"tuple[]"},{"components":[{"internalType":"enum Logic.DeletionCriterion","name":"deletionCriterion","type":"uint8"},{"internalType":"bytes","name":"blob","type":"bytes"}],"internalType":"struct Logic.ExpirableBlob[]","name":"applicationPayload","type":"tuple[]"}],"internalType":"struct Logic.AppData","name":"appData","type":"tuple"},{"internalType":"bytes","name":"proof","type":"bytes"}],"internalType":"struct Logic.VerifierInput[]","name":"logicVerifierInputs","type":"tuple[]"},{"components":[{"internalType":"bytes","name":"proof","type":"bytes"},{"components":[{"components":[{"internalType":"bytes32","name":"nullifier","type":"bytes32"},{"internalType":"bytes32","name":"logicRef","type":"bytes32"},{"internalType":"bytes32","name":"commitmentTreeRoot","type":"bytes32"}],"internalType":"struct Compliance.ConsumedRefs","name":"consumed","type":"tuple"},{"components":[{"internalType":"bytes32","name":"commitment","type":"bytes32"},{"internalType":"bytes32","name":"logicRef","type":"bytes32"}],"internalType":"struct Compliance.CreatedRefs","name":"created","type":"tuple"},{"internalType":"bytes32","name":"unitDeltaX","type":"bytes32"},{"internalType":"bytes32","name":"unitDeltaY","type":"bytes32"}],"internalType":"struct Compliance.Instance","name":"instance","type":"tuple"}],"internalType":"struct Compliance.VerifierInput[]","name":"complianceVerifierInputs","type":"tuple[]"}],"internalType":"struct Action[]","name":"actions","type":"tuple[]"},{"internalType":"bytes","name":"deltaProof","type":"bytes"},{"internalType":"bytes","name":"aggregationProof","type":"bytes"}],"internalType":"struct Transaction","name":"transaction","type":"tuple"}],"name":"execute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getRiscZeroVerifierRouter","outputs":[{"internalType":"address","name":"verifierRouter","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRiscZeroVerifierSelector","outputs":[{"internalType":"bytes4","name":"verifierSelector","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVersion","outputs":[{"internalType":"bytes32","name":"version","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"root","type":"bytes32"}],"name":"isCommitmentTreeRootContained","outputs":[{"internalType":"bool","name":"isContained","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isEmergencyStopped","outputs":[{"internalType":"bool","name":"isStopped","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"nullifier","type":"bytes32"}],"name":"isNullifierContained","outputs":[{"internalType":"bool","name":"isContained","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestCommitmentTreeRoot","outputs":[{"internalType":"bytes32","name":"root","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"nullifierAtIndex","outputs":[{"internalType":"bytes32","name":"nullifier","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nullifierCount","outputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"components":[{"internalType":"bytes32","name":"tag","type":"bytes32"},{"internalType":"bytes32","name":"verifyingKey","type":"bytes32"},{"components":[{"components":[{"internalType":"enum Logic.DeletionCriterion","name":"deletionCriterion","type":"uint8"},{"internalType":"bytes","name":"blob","type":"bytes"}],"internalType":"struct Logic.ExpirableBlob[]","name":"resourcePayload","type":"tuple[]"},{"components":[{"internalType":"enum Logic.DeletionCriterion","name":"deletionCriterion","type":"uint8"},{"internalType":"bytes","name":"blob","type":"bytes"}],"internalType":"struct Logic.ExpirableBlob[]","name":"discoveryPayload","type":"tuple[]"},{"components":[{"internalType":"enum Logic.DeletionCriterion","name":"deletionCriterion","type":"uint8"},{"internalType":"bytes","name":"blob","type":"bytes"}],"internalType":"struct Logic.ExpirableBlob[]","name":"externalPayload","type":"tuple[]"},{"components":[{"internalType":"enum Logic.DeletionCriterion","name":"deletionCriterion","type":"uint8"},{"internalType":"bytes","name":"blob","type":"bytes"}],"internalType":"struct Logic.ExpirableBlob[]","name":"applicationPayload","type":"tuple[]"}],"internalType":"struct Logic.AppData","name":"appData","type":"tuple"},{"internalType":"bytes","name":"proof","type":"bytes"}],"internalType":"struct Logic.VerifierInput[]","name":"logicVerifierInputs","type":"tuple[]"},{"components":[{"internalType":"bytes","name":"proof","type":"bytes"},{"components":[{"components":[{"internalType":"bytes32","name":"nullifier","type":"bytes32"},{"internalType":"bytes32","name":"logicRef","type":"bytes32"},{"internalType":"bytes32","name":"commitmentTreeRoot","type":"bytes32"}],"internalType":"struct Compliance.ConsumedRefs","name":"consumed","type":"tuple"},{"components":[{"internalType":"bytes32","name":"commitment","type":"bytes32"},{"internalType":"bytes32","name":"logicRef","type":"bytes32"}],"internalType":"struct Compliance.CreatedRefs","name":"created","type":"tuple"},{"internalType":"bytes32","name":"unitDeltaX","type":"bytes32"},{"internalType":"bytes32","name":"unitDeltaY","type":"bytes32"}],"internalType":"struct Compliance.Instance","name":"instance","type":"tuple"}],"internalType":"struct Compliance.VerifierInput[]","name":"complianceVerifierInputs","type":"tuple[]"}],"internalType":"struct Action[]","name":"actions","type":"tuple[]"},{"internalType":"bytes","name":"deltaProof","type":"bytes"},{"internalType":"bytes","name":"aggregationProof","type":"bytes"}],"internalType":"struct Transaction","name":"transaction","type":"tuple"},{"internalType":"bool","name":"skipRiscZeroProofVerification","type":"bool"}],"name":"simulateExecute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60c08060405234610242576060816152ec803803809161001f8285610312565b8339810103126102425780516001600160a01b038116918282036102425760208101516001600160e01b031981169182820361024257604001516001600160a01b038116908190036102425780156102ff575f80546001600160a01b03198116831782556001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a36101006003555f5f5160206152cc5f395f51905f525b61010082106102ab5750505f6001556100de610349565b507f0a2dc548ed950accb40d5d78541f3954c5e182a8ecf19e581a4f2263f61f59d260206040515f5160206152cc5f395f51905f528152a1831561029c5760209260805260a052602460405180948193633cadf44960e01b835260048301525afa90811561024e575f91610259575b50604051635c975abb60e01b815290602090829060049082906001600160a01b03165afa90811561024e575f9161020f575b508015610201575b6101f257604051614ea9908161040382396080518181816101c50152818161095e01528181611672015281816117d20152818161230701528181612d6101528181612e85015281816132e9015261410c015260a05181818161018301528181611ba8015261421c0152f35b630b1d38a360e01b5f5260045ffd5b5060ff5f5460a01c16610187565b90506020813d602011610246575b8161022a60209383610312565b8101031261024257518015158103610242575f61017f565b5f80fd5b3d915061021d565b6040513d5f823e3d90fd5b90506020813d602011610294575b8161027460209383610312565b8101031261024257516001600160a01b038116810361024257602061014d565b3d9150610267565b6367a5a71760e11b5f5260045ffd5b5f6020916003825280848484200155604051838101918083526040820152604081526102d8606082610312565b604051918291518091835e8101838152039060025afa1561024e5760015f519101906100c7565b631e4fbdf760e01b5f525f60045260245ffd5b601f909101601f19168101906001600160401b0382119082101761033557604052565b634e487b7160e01b5f52604160045260245ffd5b5f5160206152cc5f395f51905f525f5260056020525f5160206152ac5f395f51905f52546103fe57600454680100000000000000008110156103355760018101806004558110156103ea575f5160206152cc5f395f51905f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b9091018190556004545f9190915260056020525f5160206152ac5f395f51905f5255600190565b634e487b7160e01b5f52603260045260245ffd5b5f9056fe6080806040526004361015610012575f80fd5b5f3560e01c9081630d8e6e2c146133655750806331ee62421461334757806340f34d421461332a57806359ba92581461330d5780635b666b1e146132bd5780635c975abb1461329957806363a599a414613208578063715018a61461318c57806382d32ad814611d675780638da5cb5b14611d355780639ad91d4c14611cb8578063a06056f714611c98578063bdeb442d14611c41578063c1b0bed714611c15578063c44956d114611bf8578063c879dbe414611bcc578063e33845cf14611b70578063ed3cf91f146103d5578063f2fde38b14610304578063fddd48371461012a5763fe18ab9114610103575f80fd5b34610126575f600319360112610126576020600160ff600254161b604051908152f35b5f80fd5b34610126575f600319360112610126576040517f3cadf4490000000000000000000000000000000000000000000000000000000081527fffffffff000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000016600482015260208160248173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa9081156102a9575f916102b4575b50602073ffffffffffffffffffffffffffffffffffffffff916004604051809481937f5c975abb000000000000000000000000000000000000000000000000000000008352165afa9081156102a9575f9161026e575b508015610260575b6020906040519015158152f35b505f5460a01c60ff16610253565b90506020813d6020116102a1575b8161028960209383613448565b8101031261012657518015158103610126578161024b565b3d915061027c565b6040513d5f823e3d90fd5b90506020813d6020116102fc575b816102cf60209383613448565b81010312610126575173ffffffffffffffffffffffffffffffffffffffff811681036101265760206101f5565b3d91506102c2565b346101265760206003193601126101265760043573ffffffffffffffffffffffffffffffffffffffff81168091036101265761033e61346b565b80156103a95773ffffffffffffffffffffffffffffffffffffffff5f54827fffffffffffffffffffffffff00000000000000000000000000000000000000008216175f55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b7f1e4fbdf7000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346101265760206003193601126101265767ffffffffffffffff6004351161012657606060031960043536030112610126577f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c611b485760017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d6104596134b7565b61046161368a565b505f6104716004803501806134ed565b5f91505b808210611ab957826104916044600435016004356004016135c1565b9050151561049e826136f9565b916104a8816136f9565b916104b1613672565b506040516104be816133aa565b5f80825260208201528115611ab2578260011c925b601f196104f86104e2866136e1565b956104f06040519788613448565b8087526136e1565b015f5b818110611a575750508215611a4f57935b601f1961053161051b876136e1565b966105296040519889613448565b8088526136e1565b015f5b818110611a385750506040519561054a8761342b565b865260208601525f604086015260608501525f60808501525f60a085015260c084015260e083015261010082015261058c6004356004016004356004016134ed565b90505f5b818110610c1a5782608081015161061b575b6105e5816105f360207f10dd528db2c49add6545679b976df90d24c035d6a75b17f41b700e8c18ca53649451920151604051938493604085526040850190613612565b908382036020850152613612565b0390a15f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d005b61067161067a6106356024600435016004356004016135c1565b919061064b6044600435016004356004016135c1565b94909361066b60608801519388516020815160051b910120923691613950565b90614d19565b90939193614d53565b60208151910151905f5260205273ffffffffffffffffffffffffffffffffffffffff8060405f2016911690808203610bec57505060c0830151610752575b50506040810151906106c982614ca2565b15610726576105e5907f0a2dc548ed950accb40d5d78541f3954c5e182a8ecf19e581a4f2263f61f59d260207f10dd528db2c49add6545679b976df90d24c035d6a75b17f41b700e8c18ca536494604051908152a19150506105a2565b507fdb788c2b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81600411610126576107867fffffffff000000000000000000000000000000000000000000000000000000008235166141f8565b602083015160e084015161010085015190604051926107a48461340f565b835260208301908082526040840192835251926020936040516107c78682613448565b5f8152926040516107d88782613448565b5f8152945f915b87848410610a5c575050505061081d63ffffffff821662ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b938160011b9180830460021490151715610a2f5760248661086863ffffffff6028951662ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b9451947fffffffff00000000000000000000000000000000000000000000000000000000826040519882828b019b60e01b168b52805191829101868b015e8801917f919e13001cd3319be5a5a7cb189203be083674acb3fff23d05aae9c3ed86314d8584015260e01b1693846044830152805192839101604883015e010190602482015201848251919201905f5b86828210610a1b575050505090610918815f949303601f198101835282613448565b604051918291518091835e8101838152039060025afa156102a9575f519160a084015115610947575b506106b8565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016803b15610126575f926109c992604051958694859384937fab750e75000000000000000000000000000000000000000000000000000000008552606060048601526064850191613844565b907f213b3f40d7c113c1a012072fcd791fa44bf5166a2300121630bd3228e2b008276024840152604483015203915afa80156102a957610a0b575b8080610941565b5f610a1591613448565b81610a04565b8351855293840193909201916001016108f6565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b9091929695610aaf908280610a7b610a758c885161377b565b51614278565b6040519584879551918291018487015e8401908282015f8152815193849201905e01015f815203601f198101835282613448565b9482518760011b9088820460021489151715610a2f57610ad282610ad89261377b565b516142d6565b84519060018301809311610a2f5760019360048c8193610aff610ad28398610be39861377b565b7fffffffff000000000000000000000000000000000000000000000000000000008380610b5863ffffffff865160021c1662ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b610b8e63ffffffff865160021c1662ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b95846040519d8b8f82819e519384930191015e8b019260e01b1683830152805192839101602483015e01019260e01b1684830152805192839101600883015e01015f838201520301601f198101835282613448565b960191906107df565b7fe6d44b4c000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b610c3281610c2c6004803501806134ed565b90613541565b610c3f60208201826134ed565b80915060011b81810460021482151715610a2f57610c5c906136f9565b905f5b8181106119e1575050600160ff82516fffffffffffffffffffffffffffffffff811160071b67ffffffffffffffff82821c1160061b1763ffffffff82821c1160051b1761ffff82821c1160041b178282821c1160031b17600f82821c1160021b177d01010202020203030303030303030000000000000000000000000000000082821c1a179083821b1001161b610cf5816136f9565b915f5b8281106119865750505b600181116119075750610d149061376e565b5190610d2360208201826134ed565b90505f5b818110610d73575050604060019392610d61837f1cc9a0755dd734c1ebfe98b68ece200037e363eb366d0dee04e420e2f23cc010946134ed565b8351928352602083015250a101610590565b610d8a81610d8460208601866134ed565b90613581565b96610d9361368a565b5060208801906060890135805f52600560205260405f2054156118dc575060c081015186901561176457610e04610e0f93610def60e0850151608086015160011c90610ddf368561379c565b610de9838361377b565b5261377b565b505b610dfb88806134ed565b909135916138d5565b60408b013590613a95565b96610e28610e1d85806134ed565b6080840135916138d5565b60a0820135610e3561368a565b5080602083013503611730575060808136031261012657604051610e58816133f3565b8135815260208201356020820152604082013567ffffffffffffffff8111610126578201906080823603126101265760405191610e94836133f3565b803567ffffffffffffffff811161012657610eb290369083016139a1565b8352602081013567ffffffffffffffff811161012657610ed590369083016139a1565b6020840152604081013567ffffffffffffffff811161012657610efb90369083016139a1565b604084015260608101359067ffffffffffffffff821161012657610f21913691016139a1565b6060830152604081019182526060830190813567ffffffffffffffff811161012657610f509036908601613986565b6060820152610f5d61372a565b5051915160405192610f6e846133f3565b83525f602084015260408301899052606083015260c08b0151156116015750610fa7906101008b015160808c015191610de9838361377b565b505b610fc3610fb96040830183613888565b60408101906134ed565b90505f5b818110611416575050885160808a0190610fe583359183519061377b565b5261100860208b015191805190610ffb82613a68565b905260208401359261377b565b5260ff6002541660015461101b81613a68565b600155908235915f5b828110611370575050600154600160ff600254161b1461132f575b5060408a015261105b6110556040830183613888565b806134ed565b5f5b8181106112cf575050506110816110776040830183613888565b60208101906134ed565b5f5b81811061126f5750505061109d610fb96040830183613888565b5f5b8181106111fd575050506110c36110b96040830183613888565b60608101906134ed565b90915f5b8281106111815750505050606088018051604051926110e5846133aa565b60c0810135845260e060208501910135815260405193611104856133aa565b5f85525f602086015261111a8151835190614563565b15611149579161113b916001969594936020835193015190519151926145c5565b602084015282525201610d27565b604491604051917fb8a0e8a1000000000000000000000000000000000000000000000000000000008352516004830152516024820152fd5b61118c818486613541565b359060028210156101265760018092146111a7575b016110c7565b6111f57fa494dac4b7184843583f972e06783e2c3bb47f4f0137b8df52a860df07219f8c6111e36111d984888a613541565b60208101906135c1565b6040518735949092839290878461454c565b0390a26111a1565b611208818385613541565b35906002821015610126576001809214611223575b0161109f565b6112677f9c61b290f631097f56273cf4daf40df1ff9ccc33f101d464837da1f5ae18bd596112556111d9848789613541565b6040518935949092839290878461454c565b0390a261121d565b61127a818385613541565b35906002821015610126576001809214611295575b01611083565b6112c77f48243873b4752ddcb45e0d7b11c4c266583e5e099a0b798fdd9c1af7d49324f36112556111d9848789613541565b0390a261128f565b6112da818385613541565b359060028210156101265760018092146112f5575b0161105d565b6113277f3a134d01c07803003c63301717ddc4612e6c47ae408eeea3222cded532d02ae66112556111d9848789613541565b0390a26112ef565b9061136a9161133d82614a2a565b60035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b015490614829565b8a61103f565b90926001908185166113de577f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace830181905560035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b8301546113d391614829565b935b811c9101611024565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace8301546114109190614829565b936113d5565b61142d6111d982610c2c610fb96040880188613888565b81016060828203126101265781359173ffffffffffffffffffffffffffffffffffffffff831680930361012657602081013567ffffffffffffffff8111610126578261147a918301613986565b91604082013567ffffffffffffffff8111610126576114999201613986565b90604051917f33a8920300000000000000000000000000000000000000000000000000000000835260208701356004840152604060248401525f83806114e260448201866149e0565b038183885af19283156102a9575f93611585575b5082516020840120815160208301200361154a575060019392917fcddb327adb31fe5437df2a8c68301bb13a6baae432a804838caaf682506aadf19161154160405192839283614a05565b0390a201610fc7565b90506115816040519283927fc504fada00000000000000000000000000000000000000000000000000000000845260048401614a05565b0390fd5b9092503d805f833e6115978183613448565b8101906020818303126101265780519067ffffffffffffffff8211610126570181601f82011215610126578051906115ce82613934565b926115dc6040519485613448565b8284526020838301011161012657815f9260208093018386015e83010152918f6114f6565b61160b81846135c1565b600411610126577fffffffff0000000000000000000000000000000000000000000000000000000061163e9135166141f8565b60a08b015115611650575b5050610fa9565b6116a19060205f8161169973ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001694886135c1565b9590966142d6565b604051918183925191829101835e8101838152039060025afa156102a9575f5190803b156101265761170b935f93604051958694859384937fab750e7500000000000000000000000000000000000000000000000000000000855260208b01359160048601613864565b03915afa80156102a957611720575b80611649565b5f61172a91613448565b8961171a565b602092507f18f639d8000000000000000000000000000000000000000000000000000000005f52600452013560245260445ffd5b5061176f89806135c1565b600411610126577fffffffff000000000000000000000000000000000000000000000000000000006117a29135166141f8565b8560a0820151156117ba575b610e04610e0f93610df1565b5073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166117fc8a806135c1565b60205f8161181261180d368a61379c565b614278565b604051918183925191829101835e8101838152039060025afa156102a9575f5192803b15610126575f9261187e92604051958694859384937fab750e75000000000000000000000000000000000000000000000000000000008552606060048601526064850191613844565b907f919e13001cd3319be5a5a7cb189203be083674acb3fff23d05aae9c3ed86314d6024840152604483015203915afa80156102a957610e0f938892610e04926118cc575b509350506117ae565b5f6118d691613448565b8c6118c3565b7ff9849ea3000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b60011c5f5b8181106119195750610d02565b8060011b907f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103610a2f57611951828561377b565b519160018101809111610a2f5760019261196e611975928761377b565b5190614829565b61197f828661377b565b520161190c565b600190825181105f146119b05761199d818461377b565b516119a8828761377b565b525b01610cf8565b7fcc1d2f838445db7aec431df9ee8a871f40e7aa5e064fc056633ef8c60fab7b066119db828761377b565b526119aa565b6119f281610d8460208701876134ed565b908060011b81810460021482151715610a2f576020830135611a14828761377b565b5260018101809111610a2f57611a3160806001940135918661377b565b5201610c5f565b602090611a4361372a565b82828a01015201610534565b505f9361050c565b602090604051611a66816133f3565b604051611a728161340f565b5f81525f848201525f60408201528152604051611a8e816133aa565b5f81525f84820152838201525f60408201525f6060820152828289010152016104fb565b5f926104d3565b9091611acd83610c2c6004803501806134ed565b90611ae7611ade60208401846134ed565b938091506134ed565b9280915060011b9080820460021490151715610a2f57808303611b195750600191611b119161378f565b920190610475565b827fd3bee78d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f3ee5aeb5000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610126575f6003193601126101265760206040517fffffffff000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610126576020600319360112610126576004355f526005602052602060405f20541515604051908152f35b34610126575f600319360112610126576020600154604051908152f35b34610126576020600319360112610126576004355f526007602052602060405f20541515604051908152f35b34610126575f600319360112610126576004547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908111610a2f57611c89602091613645565b90549060031b1c604051908152f35b34610126575f60031936011261012657602060ff60025416604051908152f35b3461012657602060031936011261012657600435600654811015611d085760065f527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f0154604051908152602090f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b34610126575f60031936011261012657602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b346101265760406003193601126101265767ffffffffffffffff600435116101265760606003196004353603011261012657602435801515809103610126575a907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c611b485760017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d611dfa6134b7565b611e0261368a565b505f90611e136004803501806134ed565b5f91505b808210613135575050611e346044600435016004356004016135c1565b9050151591611e42816136f9565b92611e4c826136f9565b92611e55613672565b50604051611e62816133aa565b5f8082526020820152821561312e578360011c935b601f19611e8661051b876136e1565b015f5b8181106130d357505083156130cb57945b601f19611ebf611ea9886136e1565b97611eb7604051998a613448565b8089526136e1565b015f5b8181106130b457505060405196611ed88861342b565b875260208701525f604087015260608601525f608086015260a085015260c084015260e083015261010082015290611f1a6004356004016004356004016134ed565b90505f5b8181106124445750506080820151611fcf575b7f10dd528db2c49add6545679b976df90d24c035d6a75b17f41b700e8c18ca53646105e583611f776020611fa49651920151604051938493604085526040850190613612565b0390a15f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d5a9061339d565b7f6f149831000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b61067161201f611fe96024600435016004356004016135c1565b9190611fff6044600435016004356004016135c1565b94909361066b60608901519389516020815160051b910120923691613950565b60208151910151905f5260205273ffffffffffffffffffffffffffffffffffffffff8060405f2016911690808203610bec57505060c08401516120fb575b505060408201519161206e83614ca2565b156120cf576105e57f10dd528db2c49add6545679b976df90d24c035d6a75b17f41b700e8c18ca5364917f0a2dc548ed950accb40d5d78541f3954c5e182a8ecf19e581a4f2263f61f59d26020611fa496604051908152a193505050611f31565b827fdb788c2b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b816004116101265761212f7fffffffff000000000000000000000000000000000000000000000000000000008235166141f8565b602084015160e0850151610100860151906040519261214d8461340f565b835260208301908082526040840192835251926020936040516121708682613448565b5f8152926040516121818782613448565b5f8152945f915b878484106123d857505050506121c663ffffffff821662ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b938160011b9180830460021490151715610a2f5760248661221163ffffffff6028951662ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b9451947fffffffff00000000000000000000000000000000000000000000000000000000826040519882828b019b60e01b168b52805191829101868b015e8801917f919e13001cd3319be5a5a7cb189203be083674acb3fff23d05aae9c3ed86314d8584015260e01b1693846044830152805192839101604883015e010190602482015201848251919201905f5b868282106123c45750505050906122c1815f949303601f198101835282613448565b604051918291518091835e8101838152039060025afa156102a9575f519160a0850151156122f0575b5061205d565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016803b15610126575f9261237292604051958694859384937fab750e75000000000000000000000000000000000000000000000000000000008552606060048601526064850191613844565b907f213b3f40d7c113c1a012072fcd791fa44bf5166a2300121630bd3228e2b008276024840152604483015203915afa80156102a9576123b4575b80806122ea565b5f6123be91613448565b826123ad565b83518552938401939092019160010161229f565b90919296956123f1908280610a7b610a758c885161377b565b9482518760011b9088820460021489151715610a2f57610ad2826124149261377b565b84519060018301809311610a2f5760019360048c8193610aff610ad2839861243b9861377b565b96019190612188565b61245681610c2c6004803501806134ed565b61246360208201826134ed565b80915060011b81810460021482151715610a2f57612480906136f9565b905f5b81811061305d575050600160ff82516fffffffffffffffffffffffffffffffff811160071b67ffffffffffffffff82821c1160061b1763ffffffff82821c1160051b1761ffff82821c1160041b178282821c1160031b17600f82821c1160021b177d01010202020203030303030303030000000000000000000000000000000082821c1a179083821b1001161b612519816136f9565b915f5b8281106130025750505b60018111612f8a57506125389061376e565b519061254760208201826134ed565b90505f5b818110612597575050604060019392612585837f1cc9a0755dd734c1ebfe98b68ece200037e363eb366d0dee04e420e2f23cc010946134ed565b8351928352602083015250a101611f1e565b6125a881610d8460208601866134ed565b976125b161368a565b50602089019060608a0135805f52600560205260405f2054156118dc575060c0810151869015612e17576125fd61260893610def60e0850151608086015160011c90610ddf368561379c565b60408c013590613a95565b97612616610e1d85806134ed565b60a082013561262361368a565b5080602083013503611730575060808136031261012657604051612646816133f3565b8135815260208201356020820152604082013567ffffffffffffffff8111610126578201906080823603126101265760405191612682836133f3565b803567ffffffffffffffff8111610126576126a090369083016139a1565b8352602081013567ffffffffffffffff8111610126576126c390369083016139a1565b6020840152604081013567ffffffffffffffff8111610126576126e990369083016139a1565b604084015260608101359067ffffffffffffffff82116101265761270f913691016139a1565b6060830152604081019182526060830190813567ffffffffffffffff81116101265761273e9036908601613986565b606082015261274b61372a565b505191516040519261275c846133f3565b83525f602084015260408301899052606083015260c08c015115612cf05750612795906101008c015160808d015191610de9838361377b565b505b6127a7610fb96040830183613888565b90505f5b818110612b40575050895160808b01906127c983359183519061377b565b526127df60208c015191805190610ffb82613a68565b5260ff600254166001546127f281613a68565b600155908235915f5b828110612a9a575050600154600160ff600254161b14612a86575b5060408b015261282c6110556040830183613888565b5f5b818110612a26575050506128486110776040830183613888565b5f5b8181106129c657505050612864610fb96040830183613888565b5f5b818110612966575050506128806110b96040830183613888565b90915f5b8281106129065750505050606089018051604051926128a2846133aa565b60c0810135845260e0602085019101358152604051936128c1856133aa565b5f85525f60208601526128d78151835190614563565b1561114957916128f8916001969594936020835193015190519151926145c5565b60208401528252520161254b565b612911818486613541565b3590600282101561012657600180921461292c575b01612884565b61295e7fa494dac4b7184843583f972e06783e2c3bb47f4f0137b8df52a860df07219f8c6111e36111d984888a613541565b0390a2612926565b612971818385613541565b3590600282101561012657600180921461298c575b01612866565b6129be7f9c61b290f631097f56273cf4daf40df1ff9ccc33f101d464837da1f5ae18bd596112556111d9848789613541565b0390a2612986565b6129d1818385613541565b359060028210156101265760018092146129ec575b0161284a565b612a1e7f48243873b4752ddcb45e0d7b11c4c266583e5e099a0b798fdd9c1af7d49324f36112556111d9848789613541565b0390a26129e6565b612a31818385613541565b35906002821015610126576001809214612a4c575b0161282e565b612a7e7f3a134d01c07803003c63301717ddc4612e6c47ae408eeea3222cded532d02ae66112556111d9848789613541565b0390a2612a46565b90612a949161133d82614a2a565b8b612816565b9092600190818516612b08577f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace830181905560035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b830154612afd91614829565b935b811c91016127fb565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace830154612b3a9190614829565b93612aff565b612b576111d982610c2c610fb96040880188613888565b81016060828203126101265781359173ffffffffffffffffffffffffffffffffffffffff831680930361012657602081013567ffffffffffffffff81116101265782612ba4918301613986565b91604082013567ffffffffffffffff811161012657612bc39201613986565b90604051917f33a8920300000000000000000000000000000000000000000000000000000000835260208701356004840152604060248401525f8380612c0c60448201866149e0565b038183885af19283156102a9575f93612c74575b5082516020840120815160208301200361154a575060019392917fcddb327adb31fe5437df2a8c68301bb13a6baae432a804838caaf682506aadf191612c6b60405192839283614a05565b0390a2016127ab565b9092503d805f833e612c868183613448565b8101906020818303126101265780519067ffffffffffffffff8211610126570181601f8201121561012657805190612cbd82613934565b92612ccb6040519485613448565b8284526020838301011161012657815f9260208093018386015e83010152915f612c20565b612cfa81846135c1565b600411610126577fffffffff00000000000000000000000000000000000000000000000000000000612d2d9135166141f8565b60a08c015115612d3f575b5050612797565b612d889060205f8161169973ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001694886135c1565b604051918183925191829101835e8101838152039060025afa156102a9575f5190803b1561012657612df2935f93604051958694859384937fab750e7500000000000000000000000000000000000000000000000000000000855260208b01359160048601613864565b03915afa80156102a957612e07575b80612d38565b5f612e1191613448565b8a612e01565b50612e228a806135c1565b600411610126577fffffffff00000000000000000000000000000000000000000000000000000000612e559135166141f8565b8560a082015115612e6d575b6125fd61260893610df1565b5073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016612eaf8b806135c1565b60205f81612ec061180d368a61379c565b604051918183925191829101835e8101838152039060025afa156102a9575f5192803b15610126575f92612f2c92604051958694859384937fab750e75000000000000000000000000000000000000000000000000000000008552606060048601526064850191613844565b907f919e13001cd3319be5a5a7cb189203be083674acb3fff23d05aae9c3ed86314d6024840152604483015203915afa80156102a9576126089388926125fd92612f7a575b50935050612e61565b5f612f8491613448565b8d612f71565b60011c5f5b818110612f9c5750612526565b8060011b907f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103610a2f57612fd4828561377b565b519160018101809111610a2f5760019261196e612ff1928761377b565b612ffb828661377b565b5201612f8f565b600190825181105f1461302c57613019818461377b565b51613024828761377b565b525b0161251c565b7fcc1d2f838445db7aec431df9ee8a871f40e7aa5e064fc056633ef8c60fab7b06613057828761377b565b52613026565b61306e81610d8460208701876134ed565b908060011b81810460021482151715610a2f576020830135613090828761377b565b5260018101809111610a2f576130ad60806001940135918661377b565b5201612483565b6020906130bf61372a565b82828b01015201611ec2565b505f94611e9a565b6020906040516130e2816133f3565b6040516130ee8161340f565b5f81525f848201525f6040820152815260405161310a816133aa565b5f81525f84820152838201525f60408201525f606082015282828a01015201611e89565b5f93611e77565b909261314984610c2c6004803501806134ed565b9061315a611ade60208401846134ed565b9280915060011b9080820460021490151715610a2f57808303611b1957506001916131849161378f565b930190611e17565b34610126575f600319360112610126576131a461346b565b5f73ffffffffffffffffffffffffffffffffffffffff81547fffffffffffffffffffffffff000000000000000000000000000000000000000081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b34610126575f6003193601126101265761322061346b565b6132286134b7565b6132306134b7565b740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff5f5416175f557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b34610126575f60031936011261012657602060ff5f5460a01c166040519015158152f35b34610126575f60031936011261012657602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610126575f600319360112610126576020600454604051908152f35b34610126575f600319360112610126576020600654604051908152f35b34610126576020600319360112610126576020611c89600435613645565b34610126575f60031936011261012657807f312e312e3000000000000000000000000000000000000000000000000000000060209252f35b91908203918211610a2f57565b6040810190811067ffffffffffffffff8211176133c657604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6080810190811067ffffffffffffffff8211176133c657604052565b6060810190811067ffffffffffffffff8211176133c657604052565b610120810190811067ffffffffffffffff8211176133c657604052565b90601f601f19910116810190811067ffffffffffffffff8211176133c657604052565b73ffffffffffffffffffffffffffffffffffffffff5f5416330361348b57565b7f118cdaa7000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b60ff5f5460a01c166134c557565b7fd93c0665000000000000000000000000000000000000000000000000000000005f5260045ffd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610126570180359067ffffffffffffffff821161012657602001918160051b3603831361012657565b9190811015611d085760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc181360301821215610126570190565b9190811015611d085760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0181360301821215610126570190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610126570180359067ffffffffffffffff82116101265760200191813603831361012657565b90602080835192838152019201905f5b81811061362f5750505090565b8251845260209384019390920191600101613622565b600454811015611d085760045f5260205f2001905f90565b8054821015611d08575f5260205f2001905f90565b6040519061367f826133aa565b5f6020838281520152565b604051906136978261342b565b6060610100838281528260208201525f60408201526040516136b8816133aa565b5f81525f6020820152838201525f60808201525f60a08201525f60c08201528260e08201520152565b67ffffffffffffffff81116133c65760051b60200190565b90613703826136e1565b6137106040519182613448565b828152601f1961372082946136e1565b0190602036910137565b60405190613737826133f3565b815f81525f60208201525f6040820152606060405191613756836133f3565b81835281602084015281604084015281808401520152565b805115611d085760200190565b8051821015611d085760209160051b010190565b91908201809211610a2f57565b809291039160e0831261012657604051906137b6826133f3565b819360608112610126577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa060409182516137ef8161340f565b84358152602085013560208201528385013584820152855201126101265760c060609160405161381e816133aa565b83820135815260808201356020820152602085015260a081013560408501520135910152565b601f8260209493601f1993818652868601375f8582860101520116010190565b9061387e9060409396959496606084526060840191613844565b9460208201520152565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8181360301821215610126570190565b90821015611d08576138d29160051b810190613888565b90565b909291925f5b81811061390e57847f89211474000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b8461391a8284866138bb565b3514613928576001016138db565b916138d29394506138bb565b67ffffffffffffffff81116133c657601f01601f191660200190565b92919261395c82613934565b9161396a6040519384613448565b829481845281830111610126578281602093845f960137010152565b9080601f83011215610126578160206138d293359101613950565b9080601f83011215610126578135916139b9836136e1565b926139c76040519485613448565b80845260208085019160051b830101918383116101265760208101915b8383106139f357505050505090565b823567ffffffffffffffff8111610126578201906040601f1983880301126101265760405190613a22826133aa565b6020830135600281101561012657825260408301359167ffffffffffffffff831161012657613a5988602080969581960101613986565b838201528152019201916139e4565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610a2f5760010190565b93929091613aa161368a565b5081945f936020820135908082036141ca57506080823603126101265760405193613acb856133f3565b8235948581528260208201526040840194853567ffffffffffffffff8111610126578501906080823603126101265760405191613b07836133f3565b803567ffffffffffffffff811161012657613b2590369083016139a1565b8352602081013567ffffffffffffffff811161012657613b4890369083016139a1565b6020840152604081013567ffffffffffffffff811161012657613b6e90369083016139a1565b604084015260608101359067ffffffffffffffff821161012657613b94913691016139a1565b6060830152604083019182526060860192833567ffffffffffffffff811161012657613bc39036908901613986565b6060820152613bd061372a565b505191519060405192613be2846133f3565b8352600160208401526040830152606082015260c08301511561409b57613c1a9150610100830151608084015191610de9838361377b565b505b613c29610fb98585613888565b9050865b818110613ed0575050806020613c6692519187613c50608083019485519061377b565b520151815191613c5f83613a68565b905261377b565b52613c7083614cdb565b15613ea457613c826110558383613888565b855b818110613e3557505050613c9b6110778383613888565b855b818110613dc657505050613cb4610fb98383613888565b855b818110613d5357505050613ccd916110b991613888565b839291925b818110613ce0575050505050565b613ceb818386613541565b356002811015613d4f57906001809214613d06575b01613cd2565b837fa494dac4b7184843583f972e06783e2c3bb47f4f0137b8df52a860df07219f8c613d366111d984878a613541565b90613d47604051928392878461454c565b0390a2613d00565b8580fd5b613d5e818385613541565b356002811015613dc257906001809214613d79575b01613cb6565b867f9c61b290f631097f56273cf4daf40df1ff9ccc33f101d464837da1f5ae18bd59613da96111d9848789613541565b90613dba604051928392878461454c565b0390a2613d73565b8780fd5b613dd1818385613541565b356002811015613dc257906001809214613dec575b01613c9d565b867f48243873b4752ddcb45e0d7b11c4c266583e5e099a0b798fdd9c1af7d49324f3613e1c6111d9848789613541565b90613e2d604051928392878461454c565b0390a2613de6565b613e40818385613541565b356002811015613dc257906001809214613e5b575b01613c84565b867f3a134d01c07803003c63301717ddc4612e6c47ae408eeea3222cded532d02ae6613e8b6111d9848789613541565b90613e9c604051928392878461454c565b0390a2613e55565b602484847f39a940c5000000000000000000000000000000000000000000000000000000008252600452fd5b613ee46111d982610c2c610fb98a8a613888565b8101906060818303126140975780359173ffffffffffffffffffffffffffffffffffffffff831680930361409357602082013567ffffffffffffffff811161408f5781613f32918401613986565b9160408101359067ffffffffffffffff821161408057613f53929101613986565b90604051917f33a89203000000000000000000000000000000000000000000000000000000008352876004840152604060248401528b8380613f9860448201866149e0565b038183885af1928315614084578c93614000575b5082516020840120815160208301200361154a575060019392917fcddb327adb31fe5437df2a8c68301bb13a6baae432a804838caaf682506aadf191613ff760405192839283614a05565b0390a201613c2d565b9092503d808d833e6140128183613448565b8101906020818303126140805780519067ffffffffffffffff821161407c570181601f820112156140805780519061404982613934565b926140576040519485613448565b8284526020838301011161407c57818e9260208093018386015e83010152915f613fac565b8d80fd5b8c80fd5b6040513d8e823e3d90fd5b8b80fd5b8a80fd5b8980fd5b6140a582866135c1565b600411610126577fffffffff000000000000000000000000000000000000000000000000000000006140d89135166141f8565b60a0830151156140ea575b5050613c1c565b61413b9060205f8161413373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016968a6135c1565b9590946142d6565b604051918183925191829101835e8101838152039060025afa156102a9575f5192803b15610126575f9286926141a0604051968795869485947fab750e7500000000000000000000000000000000000000000000000000000000865260048601613864565b03915afa80156102a9576141b5575b806140e3565b6141c29196505f90613448565b5f945f6141af565b7f18f639d8000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fffffffff00000000000000000000000000000000000000000000000000000000807f00000000000000000000000000000000000000000000000000000000000000001691169080820361424a575050565b7f78a2221c000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b80518051916040602083015192015160208201516020815191015191606060408501519401519460405196602088015260408701526060860152608085015260a084015260c083015260e082015260e081526138d261010082613448565b606081015181516020830151909190156145435760406301000000935b015190805190815163ffffffff1661432d9062ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b916143379061486c565b6020820151805163ffffffff166143709062ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b9061437a9061486c565b90604084015192835163ffffffff166143b59062ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b936143bf9061486c565b946060015195865163ffffffff166143f99062ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b966144039061486c565b976040519a8b9a60208c015260e01b7fffffffff000000000000000000000000000000000000000000000000000000001660408b015260448a015260e01b7fffffffff000000000000000000000000000000000000000000000000000000001660648901528051602081920160688a015e87019060e01b7fffffffff0000000000000000000000000000000000000000000000000000000016606882015281516020819301606c83015e016068019060e01b7fffffffff0000000000000000000000000000000000000000000000000000000016600482015281516020819301600883015e016004019060e01b7fffffffff0000000000000000000000000000000000000000000000000000000016600482015281516020819301600883015e01600401600481015f905203600401601f19810182526138d29082613448565b60405f936142f3565b6040906138d2949281528160208201520191613844565b801580156145b5575b80156145ad575b801561459d575b614597576401000003d01960078180938181800909089180091490565b50505f90565b506401000003d01982101561457a565b508115614573565b506401000003d01981101561456c565b90939290915f9080840361480d5750506401000003d0195f9185086145ee57505090505f905f90565b6401000003d01980600181806146558180806146459a81808f800996879281808080808f81818192099987096004099780095f09928009600309089181614638818380088261339d565b81858009089d8e8361339d565b900890099380096008098361339d565b900896096002099391905b84151585816147fc575b50806147f4575b156147965780948060016401000003d01984925b6146d95750505050806146ac5750906401000003d019809281808780098092099509900990565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526012600452fd5b9297919288156147695788810491809461473c576401000003d0199083096401000003d019036401000003d0198111610a2f576401000003d0199086940893988092818102918183041490151715610a2f576147349161339d565b929083614685565b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526012600452fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c6964206e756d6265720000000000000000000000000000000000006044820152fd5b506001614671565b6401000003d019915014155f61466a565b6401000003d01992919561482094614aa7565b93909190614660565b5f906020926040519084820192835260408201526040815261484c606082613448565b604051918291518091835e8101838152039060025afa156102a9575f5190565b8051606092915f915b80831061488157505050565b9091936148c863ffffffff6020614898888761377b565b5101515160021c1662ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b9060206148d5878661377b565b5101516148e2878661377b565b515160028110156149b35760046020936149aa937fffffffff000000000000000000000000000000000000000000000000000000008680600199614949879862ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b94846040519b888d995191829101868b015e88019260e01b1683830152805192839101602483015e01019160e01b168382015203017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4810184520182613448565b94019190614875565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b90601f19601f602080948051918291828752018686015e5f8582860101520116010190565b9091614a1c6138d2936040845260408401906149e0565b9160208184039101526149e0565b600254680100000000000000008110156133c657806001614a509201600255600261365d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff829392549160031b92831b921b1916179055565b8054680100000000000000008110156133c657614a509160018201815561365d565b949291851580614c9a575b614c8e57801580614c86575b614c7c57604051608091614ad28383613448565b8236833786156147695786948580928180600180098087529781896001099c602088019d8e5282604089019d8e8c8152516001099160608a019283526040519e8f614b1c906133f3565b5190098d525190099460208b019586525190099860408901998a52519009606087019081528651885114801590614c70575b15614c1257849283808093816040519c85614b6a8f9788613448565b368737518c51614b7a908361339d565b90088452518551614b8b908361339d565b90089860208301998a5281808b8180808089518a5190099360408a019485528185518b5190096060909a01998a525180098851614bc8908361339d565b90088180875185519009600209614bdf908361339d565b90089c51935190519009614bf38c8361339d565b90089009925190519009614c07908361339d565b900894510991929190565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f557365206a6163446f75626c652066756e6374696f6e20696e737465616400006044820152fd5b50815181511415614b4e565b5092506001919050565b508215614abe565b94509092506001919050565b508115614ab2565b805f52600560205260405f2054155f14614cd657614cc1816004614a85565b600454905f52600560205260405f2055600190565b505f90565b805f52600760205260405f2054155f14614cd657614cfa816006614a85565b600654905f52600760205260405f2055600190565b600411156149b357565b8151919060418303614d4957614d429250602082015190606060408401519301515f1a90614e1a565b9192909190565b50505f9160029190565b614d5c81614d0f565b80614d65575050565b614d6e81614d0f565b60018103614d9e577ff645eedf000000000000000000000000000000000000000000000000000000005f5260045ffd5b614da781614d0f565b60028103614ddb57507ffce698f7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b600390614de781614d0f565b14614def5750565b7fd78bce0c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411614e9e579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa156102a9575f5173ffffffffffffffffffffffffffffffffffffffff811615614e9457905f905f90565b505f906001905f90565b5050505f916003919056fcedd375898c00de52e8f13b0b8e32ad9c1577fe333b1d8f9c932ae1bca6dac3cc1d2f838445db7aec431df9ee8a871f40e7aa5e064fc056633ef8c60fab7b060000000000000000000000000b144e07a0826182b6b59788c34b32bfa86fb71173c457ba00000000000000000000000000000000000000000000000000000000000000000000000000000000e9082ac8aa2fb27defdbac604921c196b884da10

Deployed Bytecode

0x6080806040526004361015610012575f80fd5b5f3560e01c9081630d8e6e2c146133655750806331ee62421461334757806340f34d421461332a57806359ba92581461330d5780635b666b1e146132bd5780635c975abb1461329957806363a599a414613208578063715018a61461318c57806382d32ad814611d675780638da5cb5b14611d355780639ad91d4c14611cb8578063a06056f714611c98578063bdeb442d14611c41578063c1b0bed714611c15578063c44956d114611bf8578063c879dbe414611bcc578063e33845cf14611b70578063ed3cf91f146103d5578063f2fde38b14610304578063fddd48371461012a5763fe18ab9114610103575f80fd5b34610126575f600319360112610126576020600160ff600254161b604051908152f35b5f80fd5b34610126575f600319360112610126576040517f3cadf4490000000000000000000000000000000000000000000000000000000081527fffffffff000000000000000000000000000000000000000000000000000000007f73c457ba0000000000000000000000000000000000000000000000000000000016600482015260208160248173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000b144e07a0826182b6b59788c34b32bfa86fb711165afa9081156102a9575f916102b4575b50602073ffffffffffffffffffffffffffffffffffffffff916004604051809481937f5c975abb000000000000000000000000000000000000000000000000000000008352165afa9081156102a9575f9161026e575b508015610260575b6020906040519015158152f35b505f5460a01c60ff16610253565b90506020813d6020116102a1575b8161028960209383613448565b8101031261012657518015158103610126578161024b565b3d915061027c565b6040513d5f823e3d90fd5b90506020813d6020116102fc575b816102cf60209383613448565b81010312610126575173ffffffffffffffffffffffffffffffffffffffff811681036101265760206101f5565b3d91506102c2565b346101265760206003193601126101265760043573ffffffffffffffffffffffffffffffffffffffff81168091036101265761033e61346b565b80156103a95773ffffffffffffffffffffffffffffffffffffffff5f54827fffffffffffffffffffffffff00000000000000000000000000000000000000008216175f55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b7f1e4fbdf7000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346101265760206003193601126101265767ffffffffffffffff6004351161012657606060031960043536030112610126577f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c611b485760017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d6104596134b7565b61046161368a565b505f6104716004803501806134ed565b5f91505b808210611ab957826104916044600435016004356004016135c1565b9050151561049e826136f9565b916104a8816136f9565b916104b1613672565b506040516104be816133aa565b5f80825260208201528115611ab2578260011c925b601f196104f86104e2866136e1565b956104f06040519788613448565b8087526136e1565b015f5b818110611a575750508215611a4f57935b601f1961053161051b876136e1565b966105296040519889613448565b8088526136e1565b015f5b818110611a385750506040519561054a8761342b565b865260208601525f604086015260608501525f60808501525f60a085015260c084015260e083015261010082015261058c6004356004016004356004016134ed565b90505f5b818110610c1a5782608081015161061b575b6105e5816105f360207f10dd528db2c49add6545679b976df90d24c035d6a75b17f41b700e8c18ca53649451920151604051938493604085526040850190613612565b908382036020850152613612565b0390a15f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d005b61067161067a6106356024600435016004356004016135c1565b919061064b6044600435016004356004016135c1565b94909361066b60608801519388516020815160051b910120923691613950565b90614d19565b90939193614d53565b60208151910151905f5260205273ffffffffffffffffffffffffffffffffffffffff8060405f2016911690808203610bec57505060c0830151610752575b50506040810151906106c982614ca2565b15610726576105e5907f0a2dc548ed950accb40d5d78541f3954c5e182a8ecf19e581a4f2263f61f59d260207f10dd528db2c49add6545679b976df90d24c035d6a75b17f41b700e8c18ca536494604051908152a19150506105a2565b507fdb788c2b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81600411610126576107867fffffffff000000000000000000000000000000000000000000000000000000008235166141f8565b602083015160e084015161010085015190604051926107a48461340f565b835260208301908082526040840192835251926020936040516107c78682613448565b5f8152926040516107d88782613448565b5f8152945f915b87848410610a5c575050505061081d63ffffffff821662ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b938160011b9180830460021490151715610a2f5760248661086863ffffffff6028951662ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b9451947fffffffff00000000000000000000000000000000000000000000000000000000826040519882828b019b60e01b168b52805191829101868b015e8801917f919e13001cd3319be5a5a7cb189203be083674acb3fff23d05aae9c3ed86314d8584015260e01b1693846044830152805192839101604883015e010190602482015201848251919201905f5b86828210610a1b575050505090610918815f949303601f198101835282613448565b604051918291518091835e8101838152039060025afa156102a9575f519160a084015115610947575b506106b8565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000b144e07a0826182b6b59788c34b32bfa86fb71116803b15610126575f926109c992604051958694859384937fab750e75000000000000000000000000000000000000000000000000000000008552606060048601526064850191613844565b907f213b3f40d7c113c1a012072fcd791fa44bf5166a2300121630bd3228e2b008276024840152604483015203915afa80156102a957610a0b575b8080610941565b5f610a1591613448565b81610a04565b8351855293840193909201916001016108f6565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b9091929695610aaf908280610a7b610a758c885161377b565b51614278565b6040519584879551918291018487015e8401908282015f8152815193849201905e01015f815203601f198101835282613448565b9482518760011b9088820460021489151715610a2f57610ad282610ad89261377b565b516142d6565b84519060018301809311610a2f5760019360048c8193610aff610ad28398610be39861377b565b7fffffffff000000000000000000000000000000000000000000000000000000008380610b5863ffffffff865160021c1662ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b610b8e63ffffffff865160021c1662ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b95846040519d8b8f82819e519384930191015e8b019260e01b1683830152805192839101602483015e01019260e01b1684830152805192839101600883015e01015f838201520301601f198101835282613448565b960191906107df565b7fe6d44b4c000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b610c3281610c2c6004803501806134ed565b90613541565b610c3f60208201826134ed565b80915060011b81810460021482151715610a2f57610c5c906136f9565b905f5b8181106119e1575050600160ff82516fffffffffffffffffffffffffffffffff811160071b67ffffffffffffffff82821c1160061b1763ffffffff82821c1160051b1761ffff82821c1160041b178282821c1160031b17600f82821c1160021b177d01010202020203030303030303030000000000000000000000000000000082821c1a179083821b1001161b610cf5816136f9565b915f5b8281106119865750505b600181116119075750610d149061376e565b5190610d2360208201826134ed565b90505f5b818110610d73575050604060019392610d61837f1cc9a0755dd734c1ebfe98b68ece200037e363eb366d0dee04e420e2f23cc010946134ed565b8351928352602083015250a101610590565b610d8a81610d8460208601866134ed565b90613581565b96610d9361368a565b5060208801906060890135805f52600560205260405f2054156118dc575060c081015186901561176457610e04610e0f93610def60e0850151608086015160011c90610ddf368561379c565b610de9838361377b565b5261377b565b505b610dfb88806134ed565b909135916138d5565b60408b013590613a95565b96610e28610e1d85806134ed565b6080840135916138d5565b60a0820135610e3561368a565b5080602083013503611730575060808136031261012657604051610e58816133f3565b8135815260208201356020820152604082013567ffffffffffffffff8111610126578201906080823603126101265760405191610e94836133f3565b803567ffffffffffffffff811161012657610eb290369083016139a1565b8352602081013567ffffffffffffffff811161012657610ed590369083016139a1565b6020840152604081013567ffffffffffffffff811161012657610efb90369083016139a1565b604084015260608101359067ffffffffffffffff821161012657610f21913691016139a1565b6060830152604081019182526060830190813567ffffffffffffffff811161012657610f509036908601613986565b6060820152610f5d61372a565b5051915160405192610f6e846133f3565b83525f602084015260408301899052606083015260c08b0151156116015750610fa7906101008b015160808c015191610de9838361377b565b505b610fc3610fb96040830183613888565b60408101906134ed565b90505f5b818110611416575050885160808a0190610fe583359183519061377b565b5261100860208b015191805190610ffb82613a68565b905260208401359261377b565b5260ff6002541660015461101b81613a68565b600155908235915f5b828110611370575050600154600160ff600254161b1461132f575b5060408a015261105b6110556040830183613888565b806134ed565b5f5b8181106112cf575050506110816110776040830183613888565b60208101906134ed565b5f5b81811061126f5750505061109d610fb96040830183613888565b5f5b8181106111fd575050506110c36110b96040830183613888565b60608101906134ed565b90915f5b8281106111815750505050606088018051604051926110e5846133aa565b60c0810135845260e060208501910135815260405193611104856133aa565b5f85525f602086015261111a8151835190614563565b15611149579161113b916001969594936020835193015190519151926145c5565b602084015282525201610d27565b604491604051917fb8a0e8a1000000000000000000000000000000000000000000000000000000008352516004830152516024820152fd5b61118c818486613541565b359060028210156101265760018092146111a7575b016110c7565b6111f57fa494dac4b7184843583f972e06783e2c3bb47f4f0137b8df52a860df07219f8c6111e36111d984888a613541565b60208101906135c1565b6040518735949092839290878461454c565b0390a26111a1565b611208818385613541565b35906002821015610126576001809214611223575b0161109f565b6112677f9c61b290f631097f56273cf4daf40df1ff9ccc33f101d464837da1f5ae18bd596112556111d9848789613541565b6040518935949092839290878461454c565b0390a261121d565b61127a818385613541565b35906002821015610126576001809214611295575b01611083565b6112c77f48243873b4752ddcb45e0d7b11c4c266583e5e099a0b798fdd9c1af7d49324f36112556111d9848789613541565b0390a261128f565b6112da818385613541565b359060028210156101265760018092146112f5575b0161105d565b6113277f3a134d01c07803003c63301717ddc4612e6c47ae408eeea3222cded532d02ae66112556111d9848789613541565b0390a26112ef565b9061136a9161133d82614a2a565b60035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b015490614829565b8a61103f565b90926001908185166113de577f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace830181905560035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b8301546113d391614829565b935b811c9101611024565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace8301546114109190614829565b936113d5565b61142d6111d982610c2c610fb96040880188613888565b81016060828203126101265781359173ffffffffffffffffffffffffffffffffffffffff831680930361012657602081013567ffffffffffffffff8111610126578261147a918301613986565b91604082013567ffffffffffffffff8111610126576114999201613986565b90604051917f33a8920300000000000000000000000000000000000000000000000000000000835260208701356004840152604060248401525f83806114e260448201866149e0565b038183885af19283156102a9575f93611585575b5082516020840120815160208301200361154a575060019392917fcddb327adb31fe5437df2a8c68301bb13a6baae432a804838caaf682506aadf19161154160405192839283614a05565b0390a201610fc7565b90506115816040519283927fc504fada00000000000000000000000000000000000000000000000000000000845260048401614a05565b0390fd5b9092503d805f833e6115978183613448565b8101906020818303126101265780519067ffffffffffffffff8211610126570181601f82011215610126578051906115ce82613934565b926115dc6040519485613448565b8284526020838301011161012657815f9260208093018386015e83010152918f6114f6565b61160b81846135c1565b600411610126577fffffffff0000000000000000000000000000000000000000000000000000000061163e9135166141f8565b60a08b015115611650575b5050610fa9565b6116a19060205f8161169973ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000b144e07a0826182b6b59788c34b32bfa86fb7111694886135c1565b9590966142d6565b604051918183925191829101835e8101838152039060025afa156102a9575f5190803b156101265761170b935f93604051958694859384937fab750e7500000000000000000000000000000000000000000000000000000000855260208b01359160048601613864565b03915afa80156102a957611720575b80611649565b5f61172a91613448565b8961171a565b602092507f18f639d8000000000000000000000000000000000000000000000000000000005f52600452013560245260445ffd5b5061176f89806135c1565b600411610126577fffffffff000000000000000000000000000000000000000000000000000000006117a29135166141f8565b8560a0820151156117ba575b610e04610e0f93610df1565b5073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000b144e07a0826182b6b59788c34b32bfa86fb711166117fc8a806135c1565b60205f8161181261180d368a61379c565b614278565b604051918183925191829101835e8101838152039060025afa156102a9575f5192803b15610126575f9261187e92604051958694859384937fab750e75000000000000000000000000000000000000000000000000000000008552606060048601526064850191613844565b907f919e13001cd3319be5a5a7cb189203be083674acb3fff23d05aae9c3ed86314d6024840152604483015203915afa80156102a957610e0f938892610e04926118cc575b509350506117ae565b5f6118d691613448565b8c6118c3565b7ff9849ea3000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b60011c5f5b8181106119195750610d02565b8060011b907f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103610a2f57611951828561377b565b519160018101809111610a2f5760019261196e611975928761377b565b5190614829565b61197f828661377b565b520161190c565b600190825181105f146119b05761199d818461377b565b516119a8828761377b565b525b01610cf8565b7fcc1d2f838445db7aec431df9ee8a871f40e7aa5e064fc056633ef8c60fab7b066119db828761377b565b526119aa565b6119f281610d8460208701876134ed565b908060011b81810460021482151715610a2f576020830135611a14828761377b565b5260018101809111610a2f57611a3160806001940135918661377b565b5201610c5f565b602090611a4361372a565b82828a01015201610534565b505f9361050c565b602090604051611a66816133f3565b604051611a728161340f565b5f81525f848201525f60408201528152604051611a8e816133aa565b5f81525f84820152838201525f60408201525f6060820152828289010152016104fb565b5f926104d3565b9091611acd83610c2c6004803501806134ed565b90611ae7611ade60208401846134ed565b938091506134ed565b9280915060011b9080820460021490151715610a2f57808303611b195750600191611b119161378f565b920190610475565b827fd3bee78d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f3ee5aeb5000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610126575f6003193601126101265760206040517fffffffff000000000000000000000000000000000000000000000000000000007f73c457ba00000000000000000000000000000000000000000000000000000000168152f35b34610126576020600319360112610126576004355f526005602052602060405f20541515604051908152f35b34610126575f600319360112610126576020600154604051908152f35b34610126576020600319360112610126576004355f526007602052602060405f20541515604051908152f35b34610126575f600319360112610126576004547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908111610a2f57611c89602091613645565b90549060031b1c604051908152f35b34610126575f60031936011261012657602060ff60025416604051908152f35b3461012657602060031936011261012657600435600654811015611d085760065f527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f0154604051908152602090f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b34610126575f60031936011261012657602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b346101265760406003193601126101265767ffffffffffffffff600435116101265760606003196004353603011261012657602435801515809103610126575a907f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c611b485760017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d611dfa6134b7565b611e0261368a565b505f90611e136004803501806134ed565b5f91505b808210613135575050611e346044600435016004356004016135c1565b9050151591611e42816136f9565b92611e4c826136f9565b92611e55613672565b50604051611e62816133aa565b5f8082526020820152821561312e578360011c935b601f19611e8661051b876136e1565b015f5b8181106130d357505083156130cb57945b601f19611ebf611ea9886136e1565b97611eb7604051998a613448565b8089526136e1565b015f5b8181106130b457505060405196611ed88861342b565b875260208701525f604087015260608601525f608086015260a085015260c084015260e083015261010082015290611f1a6004356004016004356004016134ed565b90505f5b8181106124445750506080820151611fcf575b7f10dd528db2c49add6545679b976df90d24c035d6a75b17f41b700e8c18ca53646105e583611f776020611fa49651920151604051938493604085526040850190613612565b0390a15f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005d5a9061339d565b7f6f149831000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b61067161201f611fe96024600435016004356004016135c1565b9190611fff6044600435016004356004016135c1565b94909361066b60608901519389516020815160051b910120923691613950565b60208151910151905f5260205273ffffffffffffffffffffffffffffffffffffffff8060405f2016911690808203610bec57505060c08401516120fb575b505060408201519161206e83614ca2565b156120cf576105e57f10dd528db2c49add6545679b976df90d24c035d6a75b17f41b700e8c18ca5364917f0a2dc548ed950accb40d5d78541f3954c5e182a8ecf19e581a4f2263f61f59d26020611fa496604051908152a193505050611f31565b827fdb788c2b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b816004116101265761212f7fffffffff000000000000000000000000000000000000000000000000000000008235166141f8565b602084015160e0850151610100860151906040519261214d8461340f565b835260208301908082526040840192835251926020936040516121708682613448565b5f8152926040516121818782613448565b5f8152945f915b878484106123d857505050506121c663ffffffff821662ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b938160011b9180830460021490151715610a2f5760248661221163ffffffff6028951662ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b9451947fffffffff00000000000000000000000000000000000000000000000000000000826040519882828b019b60e01b168b52805191829101868b015e8801917f919e13001cd3319be5a5a7cb189203be083674acb3fff23d05aae9c3ed86314d8584015260e01b1693846044830152805192839101604883015e010190602482015201848251919201905f5b868282106123c45750505050906122c1815f949303601f198101835282613448565b604051918291518091835e8101838152039060025afa156102a9575f519160a0850151156122f0575b5061205d565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000b144e07a0826182b6b59788c34b32bfa86fb71116803b15610126575f9261237292604051958694859384937fab750e75000000000000000000000000000000000000000000000000000000008552606060048601526064850191613844565b907f213b3f40d7c113c1a012072fcd791fa44bf5166a2300121630bd3228e2b008276024840152604483015203915afa80156102a9576123b4575b80806122ea565b5f6123be91613448565b826123ad565b83518552938401939092019160010161229f565b90919296956123f1908280610a7b610a758c885161377b565b9482518760011b9088820460021489151715610a2f57610ad2826124149261377b565b84519060018301809311610a2f5760019360048c8193610aff610ad2839861243b9861377b565b96019190612188565b61245681610c2c6004803501806134ed565b61246360208201826134ed565b80915060011b81810460021482151715610a2f57612480906136f9565b905f5b81811061305d575050600160ff82516fffffffffffffffffffffffffffffffff811160071b67ffffffffffffffff82821c1160061b1763ffffffff82821c1160051b1761ffff82821c1160041b178282821c1160031b17600f82821c1160021b177d01010202020203030303030303030000000000000000000000000000000082821c1a179083821b1001161b612519816136f9565b915f5b8281106130025750505b60018111612f8a57506125389061376e565b519061254760208201826134ed565b90505f5b818110612597575050604060019392612585837f1cc9a0755dd734c1ebfe98b68ece200037e363eb366d0dee04e420e2f23cc010946134ed565b8351928352602083015250a101611f1e565b6125a881610d8460208601866134ed565b976125b161368a565b50602089019060608a0135805f52600560205260405f2054156118dc575060c0810151869015612e17576125fd61260893610def60e0850151608086015160011c90610ddf368561379c565b60408c013590613a95565b97612616610e1d85806134ed565b60a082013561262361368a565b5080602083013503611730575060808136031261012657604051612646816133f3565b8135815260208201356020820152604082013567ffffffffffffffff8111610126578201906080823603126101265760405191612682836133f3565b803567ffffffffffffffff8111610126576126a090369083016139a1565b8352602081013567ffffffffffffffff8111610126576126c390369083016139a1565b6020840152604081013567ffffffffffffffff8111610126576126e990369083016139a1565b604084015260608101359067ffffffffffffffff82116101265761270f913691016139a1565b6060830152604081019182526060830190813567ffffffffffffffff81116101265761273e9036908601613986565b606082015261274b61372a565b505191516040519261275c846133f3565b83525f602084015260408301899052606083015260c08c015115612cf05750612795906101008c015160808d015191610de9838361377b565b505b6127a7610fb96040830183613888565b90505f5b818110612b40575050895160808b01906127c983359183519061377b565b526127df60208c015191805190610ffb82613a68565b5260ff600254166001546127f281613a68565b600155908235915f5b828110612a9a575050600154600160ff600254161b14612a86575b5060408b015261282c6110556040830183613888565b5f5b818110612a26575050506128486110776040830183613888565b5f5b8181106129c657505050612864610fb96040830183613888565b5f5b818110612966575050506128806110b96040830183613888565b90915f5b8281106129065750505050606089018051604051926128a2846133aa565b60c0810135845260e0602085019101358152604051936128c1856133aa565b5f85525f60208601526128d78151835190614563565b1561114957916128f8916001969594936020835193015190519151926145c5565b60208401528252520161254b565b612911818486613541565b3590600282101561012657600180921461292c575b01612884565b61295e7fa494dac4b7184843583f972e06783e2c3bb47f4f0137b8df52a860df07219f8c6111e36111d984888a613541565b0390a2612926565b612971818385613541565b3590600282101561012657600180921461298c575b01612866565b6129be7f9c61b290f631097f56273cf4daf40df1ff9ccc33f101d464837da1f5ae18bd596112556111d9848789613541565b0390a2612986565b6129d1818385613541565b359060028210156101265760018092146129ec575b0161284a565b612a1e7f48243873b4752ddcb45e0d7b11c4c266583e5e099a0b798fdd9c1af7d49324f36112556111d9848789613541565b0390a26129e6565b612a31818385613541565b35906002821015610126576001809214612a4c575b0161282e565b612a7e7f3a134d01c07803003c63301717ddc4612e6c47ae408eeea3222cded532d02ae66112556111d9848789613541565b0390a2612a46565b90612a949161133d82614a2a565b8b612816565b9092600190818516612b08577f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace830181905560035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b830154612afd91614829565b935b811c91016127fb565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace830154612b3a9190614829565b93612aff565b612b576111d982610c2c610fb96040880188613888565b81016060828203126101265781359173ffffffffffffffffffffffffffffffffffffffff831680930361012657602081013567ffffffffffffffff81116101265782612ba4918301613986565b91604082013567ffffffffffffffff811161012657612bc39201613986565b90604051917f33a8920300000000000000000000000000000000000000000000000000000000835260208701356004840152604060248401525f8380612c0c60448201866149e0565b038183885af19283156102a9575f93612c74575b5082516020840120815160208301200361154a575060019392917fcddb327adb31fe5437df2a8c68301bb13a6baae432a804838caaf682506aadf191612c6b60405192839283614a05565b0390a2016127ab565b9092503d805f833e612c868183613448565b8101906020818303126101265780519067ffffffffffffffff8211610126570181601f8201121561012657805190612cbd82613934565b92612ccb6040519485613448565b8284526020838301011161012657815f9260208093018386015e83010152915f612c20565b612cfa81846135c1565b600411610126577fffffffff00000000000000000000000000000000000000000000000000000000612d2d9135166141f8565b60a08c015115612d3f575b5050612797565b612d889060205f8161169973ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000b144e07a0826182b6b59788c34b32bfa86fb7111694886135c1565b604051918183925191829101835e8101838152039060025afa156102a9575f5190803b1561012657612df2935f93604051958694859384937fab750e7500000000000000000000000000000000000000000000000000000000855260208b01359160048601613864565b03915afa80156102a957612e07575b80612d38565b5f612e1191613448565b8a612e01565b50612e228a806135c1565b600411610126577fffffffff00000000000000000000000000000000000000000000000000000000612e559135166141f8565b8560a082015115612e6d575b6125fd61260893610df1565b5073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000b144e07a0826182b6b59788c34b32bfa86fb71116612eaf8b806135c1565b60205f81612ec061180d368a61379c565b604051918183925191829101835e8101838152039060025afa156102a9575f5192803b15610126575f92612f2c92604051958694859384937fab750e75000000000000000000000000000000000000000000000000000000008552606060048601526064850191613844565b907f919e13001cd3319be5a5a7cb189203be083674acb3fff23d05aae9c3ed86314d6024840152604483015203915afa80156102a9576126089388926125fd92612f7a575b50935050612e61565b5f612f8491613448565b8d612f71565b60011c5f5b818110612f9c5750612526565b8060011b907f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103610a2f57612fd4828561377b565b519160018101809111610a2f5760019261196e612ff1928761377b565b612ffb828661377b565b5201612f8f565b600190825181105f1461302c57613019818461377b565b51613024828761377b565b525b0161251c565b7fcc1d2f838445db7aec431df9ee8a871f40e7aa5e064fc056633ef8c60fab7b06613057828761377b565b52613026565b61306e81610d8460208701876134ed565b908060011b81810460021482151715610a2f576020830135613090828761377b565b5260018101809111610a2f576130ad60806001940135918661377b565b5201612483565b6020906130bf61372a565b82828b01015201611ec2565b505f94611e9a565b6020906040516130e2816133f3565b6040516130ee8161340f565b5f81525f848201525f6040820152815260405161310a816133aa565b5f81525f84820152838201525f60408201525f606082015282828a01015201611e89565b5f93611e77565b909261314984610c2c6004803501806134ed565b9061315a611ade60208401846134ed565b9280915060011b9080820460021490151715610a2f57808303611b1957506001916131849161378f565b930190611e17565b34610126575f600319360112610126576131a461346b565b5f73ffffffffffffffffffffffffffffffffffffffff81547fffffffffffffffffffffffff000000000000000000000000000000000000000081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b34610126575f6003193601126101265761322061346b565b6132286134b7565b6132306134b7565b740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff5f5416175f557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b34610126575f60031936011261012657602060ff5f5460a01c166040519015158152f35b34610126575f60031936011261012657602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000b144e07a0826182b6b59788c34b32bfa86fb711168152f35b34610126575f600319360112610126576020600454604051908152f35b34610126575f600319360112610126576020600654604051908152f35b34610126576020600319360112610126576020611c89600435613645565b34610126575f60031936011261012657807f312e312e3000000000000000000000000000000000000000000000000000000060209252f35b91908203918211610a2f57565b6040810190811067ffffffffffffffff8211176133c657604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6080810190811067ffffffffffffffff8211176133c657604052565b6060810190811067ffffffffffffffff8211176133c657604052565b610120810190811067ffffffffffffffff8211176133c657604052565b90601f601f19910116810190811067ffffffffffffffff8211176133c657604052565b73ffffffffffffffffffffffffffffffffffffffff5f5416330361348b57565b7f118cdaa7000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b60ff5f5460a01c166134c557565b7fd93c0665000000000000000000000000000000000000000000000000000000005f5260045ffd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610126570180359067ffffffffffffffff821161012657602001918160051b3603831361012657565b9190811015611d085760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc181360301821215610126570190565b9190811015611d085760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0181360301821215610126570190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610126570180359067ffffffffffffffff82116101265760200191813603831361012657565b90602080835192838152019201905f5b81811061362f5750505090565b8251845260209384019390920191600101613622565b600454811015611d085760045f5260205f2001905f90565b8054821015611d08575f5260205f2001905f90565b6040519061367f826133aa565b5f6020838281520152565b604051906136978261342b565b6060610100838281528260208201525f60408201526040516136b8816133aa565b5f81525f6020820152838201525f60808201525f60a08201525f60c08201528260e08201520152565b67ffffffffffffffff81116133c65760051b60200190565b90613703826136e1565b6137106040519182613448565b828152601f1961372082946136e1565b0190602036910137565b60405190613737826133f3565b815f81525f60208201525f6040820152606060405191613756836133f3565b81835281602084015281604084015281808401520152565b805115611d085760200190565b8051821015611d085760209160051b010190565b91908201809211610a2f57565b809291039160e0831261012657604051906137b6826133f3565b819360608112610126577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa060409182516137ef8161340f565b84358152602085013560208201528385013584820152855201126101265760c060609160405161381e816133aa565b83820135815260808201356020820152602085015260a081013560408501520135910152565b601f8260209493601f1993818652868601375f8582860101520116010190565b9061387e9060409396959496606084526060840191613844565b9460208201520152565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8181360301821215610126570190565b90821015611d08576138d29160051b810190613888565b90565b909291925f5b81811061390e57847f89211474000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b8461391a8284866138bb565b3514613928576001016138db565b916138d29394506138bb565b67ffffffffffffffff81116133c657601f01601f191660200190565b92919261395c82613934565b9161396a6040519384613448565b829481845281830111610126578281602093845f960137010152565b9080601f83011215610126578160206138d293359101613950565b9080601f83011215610126578135916139b9836136e1565b926139c76040519485613448565b80845260208085019160051b830101918383116101265760208101915b8383106139f357505050505090565b823567ffffffffffffffff8111610126578201906040601f1983880301126101265760405190613a22826133aa565b6020830135600281101561012657825260408301359167ffffffffffffffff831161012657613a5988602080969581960101613986565b838201528152019201916139e4565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610a2f5760010190565b93929091613aa161368a565b5081945f936020820135908082036141ca57506080823603126101265760405193613acb856133f3565b8235948581528260208201526040840194853567ffffffffffffffff8111610126578501906080823603126101265760405191613b07836133f3565b803567ffffffffffffffff811161012657613b2590369083016139a1565b8352602081013567ffffffffffffffff811161012657613b4890369083016139a1565b6020840152604081013567ffffffffffffffff811161012657613b6e90369083016139a1565b604084015260608101359067ffffffffffffffff821161012657613b94913691016139a1565b6060830152604083019182526060860192833567ffffffffffffffff811161012657613bc39036908901613986565b6060820152613bd061372a565b505191519060405192613be2846133f3565b8352600160208401526040830152606082015260c08301511561409b57613c1a9150610100830151608084015191610de9838361377b565b505b613c29610fb98585613888565b9050865b818110613ed0575050806020613c6692519187613c50608083019485519061377b565b520151815191613c5f83613a68565b905261377b565b52613c7083614cdb565b15613ea457613c826110558383613888565b855b818110613e3557505050613c9b6110778383613888565b855b818110613dc657505050613cb4610fb98383613888565b855b818110613d5357505050613ccd916110b991613888565b839291925b818110613ce0575050505050565b613ceb818386613541565b356002811015613d4f57906001809214613d06575b01613cd2565b837fa494dac4b7184843583f972e06783e2c3bb47f4f0137b8df52a860df07219f8c613d366111d984878a613541565b90613d47604051928392878461454c565b0390a2613d00565b8580fd5b613d5e818385613541565b356002811015613dc257906001809214613d79575b01613cb6565b867f9c61b290f631097f56273cf4daf40df1ff9ccc33f101d464837da1f5ae18bd59613da96111d9848789613541565b90613dba604051928392878461454c565b0390a2613d73565b8780fd5b613dd1818385613541565b356002811015613dc257906001809214613dec575b01613c9d565b867f48243873b4752ddcb45e0d7b11c4c266583e5e099a0b798fdd9c1af7d49324f3613e1c6111d9848789613541565b90613e2d604051928392878461454c565b0390a2613de6565b613e40818385613541565b356002811015613dc257906001809214613e5b575b01613c84565b867f3a134d01c07803003c63301717ddc4612e6c47ae408eeea3222cded532d02ae6613e8b6111d9848789613541565b90613e9c604051928392878461454c565b0390a2613e55565b602484847f39a940c5000000000000000000000000000000000000000000000000000000008252600452fd5b613ee46111d982610c2c610fb98a8a613888565b8101906060818303126140975780359173ffffffffffffffffffffffffffffffffffffffff831680930361409357602082013567ffffffffffffffff811161408f5781613f32918401613986565b9160408101359067ffffffffffffffff821161408057613f53929101613986565b90604051917f33a89203000000000000000000000000000000000000000000000000000000008352876004840152604060248401528b8380613f9860448201866149e0565b038183885af1928315614084578c93614000575b5082516020840120815160208301200361154a575060019392917fcddb327adb31fe5437df2a8c68301bb13a6baae432a804838caaf682506aadf191613ff760405192839283614a05565b0390a201613c2d565b9092503d808d833e6140128183613448565b8101906020818303126140805780519067ffffffffffffffff821161407c570181601f820112156140805780519061404982613934565b926140576040519485613448565b8284526020838301011161407c57818e9260208093018386015e83010152915f613fac565b8d80fd5b8c80fd5b6040513d8e823e3d90fd5b8b80fd5b8a80fd5b8980fd5b6140a582866135c1565b600411610126577fffffffff000000000000000000000000000000000000000000000000000000006140d89135166141f8565b60a0830151156140ea575b5050613c1c565b61413b9060205f8161413373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000b144e07a0826182b6b59788c34b32bfa86fb71116968a6135c1565b9590946142d6565b604051918183925191829101835e8101838152039060025afa156102a9575f5192803b15610126575f9286926141a0604051968795869485947fab750e7500000000000000000000000000000000000000000000000000000000865260048601613864565b03915afa80156102a9576141b5575b806140e3565b6141c29196505f90613448565b5f945f6141af565b7f18f639d8000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fffffffff00000000000000000000000000000000000000000000000000000000807f73c457ba000000000000000000000000000000000000000000000000000000001691169080820361424a575050565b7f78a2221c000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b80518051916040602083015192015160208201516020815191015191606060408501519401519460405196602088015260408701526060860152608085015260a084015260c083015260e082015260e081526138d261010082613448565b606081015181516020830151909190156145435760406301000000935b015190805190815163ffffffff1661432d9062ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b916143379061486c565b6020820151805163ffffffff166143709062ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b9061437a9061486c565b90604084015192835163ffffffff166143b59062ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b936143bf9061486c565b946060015195865163ffffffff166143f99062ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b966144039061486c565b976040519a8b9a60208c015260e01b7fffffffff000000000000000000000000000000000000000000000000000000001660408b015260448a015260e01b7fffffffff000000000000000000000000000000000000000000000000000000001660648901528051602081920160688a015e87019060e01b7fffffffff0000000000000000000000000000000000000000000000000000000016606882015281516020819301606c83015e016068019060e01b7fffffffff0000000000000000000000000000000000000000000000000000000016600482015281516020819301600883015e016004019060e01b7fffffffff0000000000000000000000000000000000000000000000000000000016600482015281516020819301600883015e01600401600481015f905203600401601f19810182526138d29082613448565b60405f936142f3565b6040906138d2949281528160208201520191613844565b801580156145b5575b80156145ad575b801561459d575b614597576401000003d01960078180938181800909089180091490565b50505f90565b506401000003d01982101561457a565b508115614573565b506401000003d01981101561456c565b90939290915f9080840361480d5750506401000003d0195f9185086145ee57505090505f905f90565b6401000003d01980600181806146558180806146459a81808f800996879281808080808f81818192099987096004099780095f09928009600309089181614638818380088261339d565b81858009089d8e8361339d565b900890099380096008098361339d565b900896096002099391905b84151585816147fc575b50806147f4575b156147965780948060016401000003d01984925b6146d95750505050806146ac5750906401000003d019809281808780098092099509900990565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526012600452fd5b9297919288156147695788810491809461473c576401000003d0199083096401000003d019036401000003d0198111610a2f576401000003d0199086940893988092818102918183041490151715610a2f576147349161339d565b929083614685565b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526012600452fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c6964206e756d6265720000000000000000000000000000000000006044820152fd5b506001614671565b6401000003d019915014155f61466a565b6401000003d01992919561482094614aa7565b93909190614660565b5f906020926040519084820192835260408201526040815261484c606082613448565b604051918291518091835e8101838152039060025afa156102a9575f5190565b8051606092915f915b80831061488157505050565b9091936148c863ffffffff6020614898888761377b565b5101515160021c1662ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b9060206148d5878661377b565b5101516148e2878661377b565b515160028110156149b35760046020936149aa937fffffffff000000000000000000000000000000000000000000000000000000008680600199614949879862ff00ff63ff00ff008260081b169160081c161763ffffffff808260101b169160101c161790565b94846040519b888d995191829101868b015e88019260e01b1683830152805192839101602483015e01019160e01b168382015203017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe4810184520182613448565b94019190614875565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b90601f19601f602080948051918291828752018686015e5f8582860101520116010190565b9091614a1c6138d2936040845260408401906149e0565b9160208184039101526149e0565b600254680100000000000000008110156133c657806001614a509201600255600261365d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff829392549160031b92831b921b1916179055565b8054680100000000000000008110156133c657614a509160018201815561365d565b949291851580614c9a575b614c8e57801580614c86575b614c7c57604051608091614ad28383613448565b8236833786156147695786948580928180600180098087529781896001099c602088019d8e5282604089019d8e8c8152516001099160608a019283526040519e8f614b1c906133f3565b5190098d525190099460208b019586525190099860408901998a52519009606087019081528651885114801590614c70575b15614c1257849283808093816040519c85614b6a8f9788613448565b368737518c51614b7a908361339d565b90088452518551614b8b908361339d565b90089860208301998a5281808b8180808089518a5190099360408a019485528185518b5190096060909a01998a525180098851614bc8908361339d565b90088180875185519009600209614bdf908361339d565b90089c51935190519009614bf38c8361339d565b90089009925190519009614c07908361339d565b900894510991929190565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f557365206a6163446f75626c652066756e6374696f6e20696e737465616400006044820152fd5b50815181511415614b4e565b5092506001919050565b508215614abe565b94509092506001919050565b508115614ab2565b805f52600560205260405f2054155f14614cd657614cc1816004614a85565b600454905f52600560205260405f2055600190565b505f90565b805f52600760205260405f2054155f14614cd657614cfa816006614a85565b600654905f52600760205260405f2055600190565b600411156149b357565b8151919060418303614d4957614d429250602082015190606060408401519301515f1a90614e1a565b9192909190565b50505f9160029190565b614d5c81614d0f565b80614d65575050565b614d6e81614d0f565b60018103614d9e577ff645eedf000000000000000000000000000000000000000000000000000000005f5260045ffd5b614da781614d0f565b60028103614ddb57507ffce698f7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b600390614de781614d0f565b14614def5750565b7fd78bce0c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411614e9e579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa156102a9575f5173ffffffffffffffffffffffffffffffffffffffff811615614e9457905f905f90565b505f906001905f90565b5050505f916003919056

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

0000000000000000000000000b144e07a0826182b6b59788c34b32bfa86fb71173c457ba00000000000000000000000000000000000000000000000000000000000000000000000000000000e9082ac8aa2fb27defdbac604921c196b884da10

-----Decoded View---------------
Arg [0] : riscZeroVerifierRouter (address): 0x0b144E07A0826182B6b59788c34b32Bfa86Fb711
Arg [1] : riscZeroVerifierSelector (bytes4): 0x73c457ba
Arg [2] : emergencyStopCaller (address): 0xE9082Ac8Aa2Fb27DEfDBAC604921C196b884Da10

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000000b144e07a0826182b6b59788c34b32bfa86fb711
Arg [1] : 73c457ba00000000000000000000000000000000000000000000000000000000
Arg [2] : 000000000000000000000000e9082ac8aa2fb27defdbac604921c196b884da10


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
0x094FCC095323080e71a037b2B1e3519c07dd84F8
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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.