ETH Price: $2,869.23 (-2.71%)

Contract

0x000000000000790009689f43bAedb61D67D45bB8

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

ContractCreator

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Parent Transaction Hash Block From To
3999205892025-11-13 19:23:0873 days ago1763061788  Contract Creation0 ETH

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Tribunal

Compiler Version
v0.8.30+commit.73712a01

Optimization Enabled:
Yes with 4294967295 runs

Other Settings:
cancun EvmVersion
File 1 of 41 : Tribunal.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {LibBytes} from "solady/utils/LibBytes.sol";
import {ValidityLib} from "the-compact/src/lib/ValidityLib.sol";
import {EfficiencyLib} from "the-compact/src/lib/EfficiencyLib.sol";
import {FixedPointMathLib} from "solady/utils/FixedPointMathLib.sol";
import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol";
import {SignatureCheckerLib} from "solady/utils/SignatureCheckerLib.sol";
import {BlockNumberish} from "./BlockNumberish.sol";
import {PriceCurveLib} from "./lib/PriceCurveLib.sol";
import {BatchCompact, Lock, LOCK_TYPEHASH} from "the-compact/src/types/EIP712Types.sol";
import {ITheCompactClaims} from "the-compact/src/interfaces/ITheCompactClaims.sol";
import {ITheCompact} from "the-compact/src/interfaces/ITheCompact.sol";
import {IOnChainAllocation} from "the-compact/src/interfaces/IOnChainAllocation.sol";
import {BatchClaim as CompactBatchClaim} from "the-compact/src/types/BatchClaims.sol";
import {BatchClaimComponent, Component} from "the-compact/src/types/Components.sol";
import {ITribunalCallback} from "./interfaces/ITribunalCallback.sol";
import {IDispatchCallback} from "./interfaces/IDispatchCallback.sol";
import {ITribunal} from "./interfaces/ITribunal.sol";
import {
    Mandate,
    FillParameters,
    FillComponent,
    FillRecipient,
    FillRequirement,
    RecipientCallback,
    Adjustment,
    DispatchParameters,
    BatchClaim,
    DispositionDetails,
    ArgDetail
} from "./types/TribunalStructs.sol";
import {DomainLib} from "./lib/DomainLib.sol";
import {IRecipientCallback} from "./interfaces/IRecipientCallback.sol";
import {
    MANDATE_TYPEHASH,
    MANDATE_FILL_TYPEHASH,
    MANDATE_FILL_COMPONENT_TYPEHASH,
    MANDATE_RECIPIENT_CALLBACK_TYPEHASH,
    MANDATE_BATCH_COMPACT_TYPEHASH,
    MANDATE_LOCK_TYPEHASH,
    COMPACT_TYPEHASH_WITH_MANDATE,
    ADJUSTMENT_TYPEHASH,
    WITNESS_TYPESTRING
} from "./types/TribunalTypeHashes.sol";

/**
 * @title Tribunal
 * @author 0age
 * @custom:version 0 (Proof-of-concept)
 * @custom:security-contact [email protected]
 * @notice Tribunal is a protocol that runs competitive auctions for claims against resource locks. It integrates with The Compact as the mechanism for settling claims after fills occur.
 * @dev This contract is under active development; contributions, reviews, and feedback are greatly appreciated.
 */
contract Tribunal is BlockNumberish, ITribunal {
    // ======== Libraries ========
    using ValidityLib for uint256;
    using FixedPointMathLib for uint256;
    using SafeTransferLib for address;
    using EfficiencyLib for bool;
    using PriceCurveLib for uint256[];
    using PriceCurveLib for uint256;
    using SignatureCheckerLib for address;
    using DomainLib for bytes32;

    // ======== Constants ========
    /// @notice The Compact contract instance used for depositing into resource
    /// locks, registering compacts utilizing those locks, and processing claims
    /// on compacts.
    ITheCompact public constant THE_COMPACT =
        ITheCompact(0x00000000000000171ede64904551eeDF3C6C9788);

    /// @notice Base scaling factor (1e18 = neutral, no scaling).
    uint256 public constant BASE_SCALING_FACTOR = 1e18;

    /// @notice keccak256("_REENTRANCY_GUARD_SLOT")
    bytes32 private constant _REENTRANCY_GUARD_SLOT =
        0x929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c0;

    /// @notice Hash of an empty bytes array, used for empty recipient callbacks.
    bytes32 private constant _EMPTY_HASH =
        0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;

    /// @notice Address bit offset in validity conditions (160 bits = 0xa0).
    uint256 private constant _ADDRESS_BITS = 0xa0;

    // ======== Immutables ========
    // Chain ID at deployment, used for triggering EIP-712 domain separator updates.
    uint256 private immutable _INITIAL_CHAIN_ID;

    // Initial EIP-712 domain separator, computed at deployment time.
    bytes32 private immutable _INITIAL_DOMAIN_SEPARATOR;

    // ======== Storage ========
    /// @notice Mapping of claim hashes to claimants (or sponsor if cancelled).
    mapping(bytes32 => bytes32) private _dispositions;

    /// @notice Mapping of claim hashes to claim reduction scaling factors (only set when < 1e18 or cancelled).
    mapping(bytes32 => uint256) private _claimReductionScalingFactors;

    // ======== Modifiers ========
    modifier nonReentrant() {
        assembly ("memory-safe") {
            // Check if reentrancy guard is already set.
            if tload(_REENTRANCY_GUARD_SLOT) {
                // revert ReentrancyGuard();
                mstore(0, 0x8beb9d16)
                revert(0x1c, 0x04)
            }

            // Set the reentrancy guard to the current caller.
            tstore(_REENTRANCY_GUARD_SLOT, caller())
        }

        // Continue with function execution.
        _;

        assembly ("memory-safe") {
            // Clear the reentrancy guard.
            tstore(_REENTRANCY_GUARD_SLOT, 0)
        }
    }

    /**
     * @notice Constructor that initializes immutable variables,
     * capturing the initial chain ID and domain separator.
     */
    constructor() {
        _INITIAL_CHAIN_ID = block.chainid;
        _INITIAL_DOMAIN_SEPARATOR = DomainLib.toCurrentDomainSeparator();
    }

    /**
     * @notice Fallback function to allow the contract to receive native tokens (ETH).
     * @dev This is necessary for receiving native tokens during claimAndFill and
     * settleOrRegister operations, for accounting for variable fill amount requirements
     * based on the auction duration or transaction parameters, and for handling refunds
     * of excess value sent during dispatch operations that require it.
     */
    receive() external payable {}

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

    /// @inheritdoc ITribunal
    function fill(
        BatchCompact calldata compact,
        FillParameters calldata mandate,
        Adjustment calldata adjustment,
        bytes32[] calldata fillHashes,
        bytes32 claimant,
        uint256 fillBlock
    )
        external
        payable
        nonReentrant
        returns (
            bytes32 claimHash,
            bytes32 mandateHash,
            uint256[] memory fillAmounts,
            uint256[] memory claimAmounts
        )
    {
        // Validate fill block or normalize to current block if none was provided.
        fillBlock = _validateFillBlock(fillBlock);

        // Execute the fill operation.
        (claimHash, mandateHash, fillAmounts, claimAmounts) =
            _fill(compact, mandate, adjustment, claimant, fillBlock, fillHashes);

        // Return any unused native tokens to the caller.
        uint256 remaining = address(this).balance;
        if (remaining > 0) {
            msg.sender.safeTransferETH(remaining);
        }

        return (claimHash, mandateHash, fillAmounts, claimAmounts);
    }

    /// @inheritdoc ITribunal
    function fillAndDispatch(
        BatchCompact calldata compact,
        FillParameters calldata mandate,
        Adjustment calldata adjustment,
        bytes32[] calldata fillHashes,
        bytes32 claimant,
        uint256 fillBlock,
        DispatchParameters calldata dispatchParameters
    )
        external
        payable
        nonReentrant
        returns (
            bytes32 claimHash,
            bytes32 mandateHash,
            uint256[] memory fillAmounts,
            uint256[] memory claimAmounts
        )
    {
        // Execute the fill operation with validated or normalized block number.
        (claimHash, mandateHash, fillAmounts, claimAmounts) = _fill(
            compact, mandate, adjustment, claimant, _validateFillBlock(fillBlock), fillHashes
        );

        // Trigger dispatch callback to relay information to provided target.
        _performDispatchCallback(
            compact, mandateHash, claimHash, claimant, claimAmounts, dispatchParameters
        );

        return (claimHash, mandateHash, fillAmounts, claimAmounts);
    }

    /// @inheritdoc ITribunal
    function claimAndFill(
        BatchClaim calldata claim,
        FillParameters calldata mandate,
        Adjustment calldata adjustment,
        bytes32[] calldata fillHashes,
        bytes32 claimant,
        uint256 fillBlock
    )
        external
        payable
        nonReentrant
        returns (
            bytes32 claimHash,
            bytes32 mandateHash,
            uint256[] memory fillAmounts,
            uint256[] memory claimAmounts
        )
    {
        // Execute claim and fill operations with validated or normalized block number.
        return _claimAndFill(
            claim, mandate, adjustment, claimant, _validateFillBlock(fillBlock), fillHashes
        );
    }

    /// @inheritdoc ITribunal
    function dispatch(
        BatchCompact calldata compact,
        bytes32 mandateHash,
        DispatchParameters calldata dispatchParams
    ) external payable nonReentrant returns (bytes32 claimHash, uint256[] memory claimAmounts) {
        // Derive claim hash.
        claimHash = deriveClaimHash(compact, mandateHash);

        // Check if claim has been filled.
        bytes32 claimant = _dispositions[claimHash];
        if (claimant == bytes32(0)) {
            revert DispatchNotAvailable();
        }

        // Get the stored scaling factor (1e18 if not stored).
        uint256 scalingFactor = _getClaimReductionScalingFactor(claimHash);

        // Compute claim amounts using the stored scaling factor.
        claimAmounts = new uint256[](compact.commitments.length);
        for (uint256 i = 0; i < compact.commitments.length; i++) {
            claimAmounts[i] = compact.commitments[i].amount.mulWad(scalingFactor);
        }

        // Trigger dispatch callback to relay information to provided target.
        _performDispatchCallback(
            compact, mandateHash, claimHash, claimant, claimAmounts, dispatchParams
        );

        return (claimHash, claimAmounts);
    }

    /// @inheritdoc ITribunal
    function settleOrRegister(
        bytes32 sourceClaimHash,
        BatchCompact calldata compact,
        bytes32 mandateHash,
        address recipient,
        bytes calldata context
    ) external payable nonReentrant returns (bytes32 registeredClaimHash) {
        // Only single-token settlements are supported.
        if (compact.commitments.length != 1) {
            revert InvalidCommitmentsArray();
        }
        Lock calldata commitment = compact.commitments[0];

        // Check if claim has been filled.
        bytes32 claimant = _dispositions[sourceClaimHash];

        // Handle claimant transfer if available.
        if (claimant != bytes32(0)) {
            _handleClaimantTransfer(commitment, claimant);
            return bytes32(0);
        }

        // Ensure recipient is set (default to sponsor if not provided).
        address sponsor = compact.sponsor;
        assembly ("memory-safe") {
            // Use branchless logic to assign sponsor as recipient if not provided.
            recipient := xor(recipient, mul(iszero(recipient), sponsor))
        }

        // An empty lockTag indicates a direct transfer.
        if (commitment.lockTag == bytes12(0)) {
            _handleDirectTransfer(commitment, recipient);
            return bytes32(0);
        }

        // Prepare ids and amounts.
        (uint256[2][] memory idsAndAmounts, uint256 callValue) = _prepareIdsAndAmounts(commitment);

        // Handle deposit without registration.
        if (mandateHash == bytes32(0)) {
            THE_COMPACT.batchDeposit{value: callValue}(idsAndAmounts, recipient);
            return bytes32(0);
        }

        // Handle registration with or without onchain allocation based on provided nonce.
        if (compact.nonce == 0) {
            registeredClaimHash =
                _handleOnChainAllocation(compact, idsAndAmounts, callValue, mandateHash, context);
        } else {
            registeredClaimHash =
                _handleDirectRegistration(compact, idsAndAmounts, callValue, mandateHash);
        }
        return registeredClaimHash;
    }

    /// @inheritdoc ITribunal
    function cancel(BatchCompact calldata compact, bytes32 mandateHash)
        external
        nonReentrant
        returns (bytes32 claimHash)
    {
        // Cancel and return the associated claim hash.
        return _cancel(compact, mandateHash);
    }

    /// @inheritdoc ITribunal
    function cancelAndDispatch(
        BatchCompact calldata compact,
        bytes32 mandateHash,
        DispatchParameters calldata dispatchParams
    ) external payable nonReentrant returns (bytes32 claimHash) {
        // Cancel and derive the associated claim hash.
        claimHash = _cancel(compact, mandateHash);

        // Create zero claim amounts for dispatch.
        uint256[] memory zeroClaimAmounts = new uint256[](compact.commitments.length);

        // Trigger dispatch callback with zero amounts.
        _performDispatchCallback(
            compact,
            mandateHash,
            claimHash,
            bytes32(uint256(uint160(msg.sender))),
            zeroClaimAmounts,
            dispatchParams
        );

        return claimHash;
    }

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

    /// @inheritdoc ITribunal
    function filled(bytes32 claimHash) external view returns (bytes32) {
        return _dispositions[claimHash];
    }

    /// @inheritdoc ITribunal
    function claimReductionScalingFactor(bytes32 claimHash)
        external
        view
        returns (uint256 scalingFactor)
    {
        return _getClaimReductionScalingFactor(claimHash);
    }

    /// @inheritdoc ITribunal
    function getDispositionDetails(bytes32[] calldata claimHashes)
        external
        view
        returns (DispositionDetails[] memory details)
    {
        details = new DispositionDetails[](claimHashes.length);

        // Populate disposition details for each claim hash.
        for (uint256 i = 0; i < claimHashes.length; i++) {
            bytes32 claimHash = claimHashes[i];
            details[i] = DispositionDetails({
                claimant: _dispositions[claimHash],
                scalingFactor: _getClaimReductionScalingFactor(claimHash)
            });
        }

        return details;
    }

    /// @inheritdoc ITribunal
    function deriveAmountsFromComponents(
        Lock[] calldata maximumClaimAmounts,
        FillComponent[] calldata components,
        uint256[] memory priceCurve,
        uint256 targetBlock,
        uint256 fillBlock,
        uint256 baselinePriorityFee,
        uint256 scalingFactor
    ) external view returns (uint256[] memory fillAmounts, uint256[] memory claimAmounts) {
        // Calculate the current scaling factor from price curve.
        uint256 currentScalingFactor =
            _calculateCurrentScalingFactor(priceCurve, targetBlock, fillBlock);

        // Validate scaling direction.
        if (!scalingFactor.sharesScalingDirection(currentScalingFactor)) {
            revert PriceCurveLib.InvalidPriceCurveParameters();
        }

        // Calculate scaling multiplier and determine mode.
        (uint256 scalingMultiplier, bool useExactIn) =
            _calculateScalingMultiplier(currentScalingFactor, scalingFactor, baselinePriorityFee);

        // Calculate fill amounts.
        fillAmounts = _calculateFillAmounts(components, scalingMultiplier, useExactIn);

        // Calculate claim amounts.
        claimAmounts = _calculateClaimAmounts(maximumClaimAmounts, scalingMultiplier, useExactIn);

        return (fillAmounts, claimAmounts);
    }

    /// @inheritdoc ITribunal
    function extsload(bytes32 slot) external view returns (bytes32) {
        assembly ("memory-safe") {
            mstore(0, sload(slot))
            return(0, 0x20)
        }
    }

    /// @inheritdoc ITribunal
    function extsload(bytes32[] calldata slots) external view returns (bytes32[] memory) {
        assembly ("memory-safe") {
            let memptr := mload(0x40)
            let start := memptr

            // For abi encoding the response - the array will be found at 0x20.
            mstore(memptr, 0x20)

            // Next, store the length of the return array.
            mstore(add(memptr, 0x20), slots.length)

            // Update memptr to the first location to hold an array entry.
            memptr := add(memptr, 0x40)

            // A left bit-shift of 5 is equivalent to multiplying by 32 but costs less gas.
            let end := add(memptr, shl(5, slots.length))

            let calldataptr := slots.offset
            for {} 1 {} {
                mstore(memptr, sload(calldataload(calldataptr)))
                memptr := add(memptr, 0x20)
                if iszero(lt(memptr, end)) { break }
                calldataptr := add(calldataptr, 0x20)
            }

            return(start, sub(end, start))
        }
    }

    /// @inheritdoc ITribunal
    function reentrancyGuardStatus() external view returns (address lockHolder) {
        assembly ("memory-safe") {
            lockHolder := tload(_REENTRANCY_GUARD_SLOT)
        }
    }

    // ======== External Pure Functions ========

    /// @inheritdoc ITribunal
    function name() external pure returns (string memory) {
        return "Tribunal";
    }

    /// @inheritdoc ITribunal
    function getCompactWitnessDetails()
        external
        pure
        returns (string memory witnessTypeString, ArgDetail[] memory details)
    {
        // Build the witness typestring.
        witnessTypeString = string.concat("Mandate(", WITNESS_TYPESTRING, ")");

        // Build the details array with a single element.
        details = new ArgDetail[](1);
        details[0] = ArgDetail({
            tokenPath: "fills[].components[].fillToken",
            argPath: "fills[].components[].minimumFillAmount",
            description: "Output token and minimum amount for each fill component in the Fills array"
        });
    }

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

    /// @inheritdoc ITribunal
    function deriveMandateHash(Mandate calldata mandate) public view returns (bytes32) {
        return
            keccak256(
                abi.encode(MANDATE_TYPEHASH, mandate.adjuster, deriveFillsHash(mandate.fills))
            );
    }

    /// @inheritdoc ITribunal
    function deriveFillsHash(FillParameters[] calldata fills) public view returns (bytes32) {
        bytes32[] memory fillHashes = new bytes32[](fills.length);

        // Hash each fill individually using EIP-712.
        for (uint256 i = 0; i < fills.length; ++i) {
            fillHashes[i] = deriveFillHash(fills[i]);
        }

        // Concatenate and hash all fill hashes together.
        return keccak256(abi.encodePacked(fillHashes));
    }

    /// @inheritdoc ITribunal
    function deriveFillHash(FillParameters calldata targetFill) public view returns (bytes32) {
        return keccak256(
            abi.encode(
                MANDATE_FILL_TYPEHASH,
                block.chainid,
                address(this),
                targetFill.expires,
                deriveFillComponentsHash(targetFill.components),
                targetFill.baselinePriorityFee,
                targetFill.scalingFactor,
                keccak256(abi.encodePacked(targetFill.priceCurve)),
                deriveRecipientCallbackHash(targetFill.recipientCallback),
                targetFill.salt
            )
        );
    }

    /// @inheritdoc ITribunal
    function deriveAmounts(
        Lock[] calldata maximumClaimAmounts,
        uint256[] memory priceCurve,
        uint256 targetBlock,
        uint256 fillBlock,
        uint256 minimumFillAmount,
        uint256 baselinePriorityFee,
        uint256 scalingFactor
    ) public view returns (uint256 fillAmount, uint256[] memory claimAmounts) {
        uint256 currentScalingFactor = BASE_SCALING_FACTOR;

        // Validate the target block if one was provided.
        if (targetBlock != 0) {
            // Ensure the target block does not exceed the fill block.
            if (targetBlock > fillBlock) {
                revert InvalidTargetBlock(fillBlock, targetBlock);
            }

            // Derive the total blocks passed since the target block.
            uint256 blocksPassed;
            unchecked {
                blocksPassed = fillBlock - targetBlock;
            }

            // Examine price curve and derive scaling factor modification.
            currentScalingFactor = priceCurve.getCalculatedValues(blocksPassed);
        } else {
            // Require that no price curve has been supplied.
            if (priceCurve.length != 0) {
                revert InvalidTargetBlockDesignation();
            }
        }

        // Ensure that the scaling direction is not inconsistent.
        if (!scalingFactor.sharesScalingDirection(currentScalingFactor)) {
            revert PriceCurveLib.InvalidPriceCurveParameters();
        }

        // Get the priority fee above baseline.
        uint256 priorityFeeAboveBaseline = _getPriorityFee(baselinePriorityFee);
        claimAmounts = new uint256[](maximumClaimAmounts.length);

        // Calculate the scaling multiplier based on priority fee.
        uint256 scalingMultiplier;

        // Determine whether to increase fill amounts (exact-in) or decrease claim amounts (exact-out).
        // When neutral (scalingFactor == 1e18), determine mode from currentScalingFactor.
        if ((scalingFactor > BASE_SCALING_FACTOR)
            .or(
                scalingFactor == BASE_SCALING_FACTOR && currentScalingFactor >= BASE_SCALING_FACTOR
            )) {
            // For exact-in, increase fill amount and use maximum claim amounts.
            scalingMultiplier = currentScalingFactor
                + ((scalingFactor - BASE_SCALING_FACTOR) * priorityFeeAboveBaseline);
            fillAmount = minimumFillAmount.mulWadUp(scalingMultiplier);

            // Copy maximum claim amounts unchanged.
            for (uint256 i = 0; i < claimAmounts.length; i++) {
                claimAmounts[i] = maximumClaimAmounts[i].amount;
            }
        } else {
            // For exact-out, decrease claim amount.
            scalingMultiplier = currentScalingFactor
                - ((BASE_SCALING_FACTOR - scalingFactor) * priorityFeeAboveBaseline);
            fillAmount = minimumFillAmount;

            // Apply scaling to maximum claim amounts.
            for (uint256 i = 0; i < claimAmounts.length; i++) {
                claimAmounts[i] = maximumClaimAmounts[i].amount.mulWad(scalingMultiplier);
            }
        }

        return (fillAmount, claimAmounts);
    }

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

    /// @inheritdoc ITribunal
    function deriveFillComponentHash(FillComponent calldata component)
        public
        pure
        returns (bytes32)
    {
        return keccak256(
            abi.encode(
                MANDATE_FILL_COMPONENT_TYPEHASH,
                component.fillToken,
                component.minimumFillAmount,
                component.recipient,
                component.applyScaling
            )
        );
    }

    /// @inheritdoc ITribunal
    function deriveFillComponentsHash(FillComponent[] calldata components)
        public
        pure
        returns (bytes32)
    {
        bytes32[] memory componentHashes = new bytes32[](components.length);

        // Hash each fill component individually using EIP-712.
        for (uint256 i = 0; i < components.length; ++i) {
            componentHashes[i] = deriveFillComponentHash(components[i]);
        }

        // Concatenate and hash all fill component hashes together.
        return keccak256(abi.encodePacked(componentHashes));
    }

    /// @inheritdoc ITribunal
    function deriveRecipientCallbackHash(RecipientCallback[] calldata recipientCallback)
        public
        pure
        returns (bytes32)
    {
        // Return pre-computed empty hash if no callback is specified.
        if (recipientCallback.length == 0) {
            return _EMPTY_HASH;
        } else if (recipientCallback.length != 1) {
            // Only a single callback is supported; revert if multiple provided.
            revert InvalidRecipientCallbackLength();
        }

        RecipientCallback calldata callback = recipientCallback[0];

        // Compute EIP-712 hash of the callback structure.
        return keccak256(
            abi.encodePacked(
                keccak256(
                    abi.encode(
                        MANDATE_RECIPIENT_CALLBACK_TYPEHASH,
                        callback.chainId,
                        _deriveClaimHash(
                            callback.compact,
                            callback.mandateHash,
                            MANDATE_LOCK_TYPEHASH,
                            MANDATE_BATCH_COMPACT_TYPEHASH
                        ),
                        callback.context
                    )
                )
            )
        );
    }

    /// @inheritdoc ITribunal
    function deriveClaimHash(BatchCompact calldata compact, bytes32 mandateHash)
        public
        pure
        returns (bytes32)
    {
        return _deriveClaimHash(compact, mandateHash, LOCK_TYPEHASH, COMPACT_TYPEHASH_WITH_MANDATE);
    }

    // ======== Internal State-changing Functions ========

    /**
     * @notice Internal implementation of a standard fill.
     * @dev Fillers must provide all required output tokens and have granted token approvals to Tribunal.
     * Native tokens (ETH) must be included as msg.value. The function validates the mandate hasn't expired,
     * verifies the adjuster's signature, validates validity conditions, calculates fill and claim amounts,
     * marks the claim as filled, transfers tokens to recipients, and triggers recipient callbacks if specified.
     * @param compact The compact parameters.
     * @param mandate The fill conditions and amount derivation parameters.
     * @param adjustment The adjustment provided by the adjuster for the fill (includes adjuster and authorization).
     * @param claimant The recipient of claimed tokens on the claim chain (lock tag ++ address).
     * @param fillBlock The block number to target for the fill (must be current block).
     * @param fillHashes An array of the hashes of each fill in the mandate.
     * @return claimHash The derived claim hash.
     * @return mandateHash The derived mandate hash.
     * @return fillAmounts The amounts of tokens to be filled for each component.
     * @return claimAmounts The amounts of each token to be claimed.
     */
    function _fill(
        BatchCompact calldata compact,
        FillParameters calldata mandate,
        Adjustment calldata adjustment,
        bytes32 claimant,
        uint256 fillBlock,
        bytes32[] calldata fillHashes
    )
        internal
        returns (
            bytes32 claimHash,
            bytes32 mandateHash,
            uint256[] memory fillAmounts,
            uint256[] memory claimAmounts
        )
    {
        // Validate fill conditions and derive mandate hash.
        mandateHash = _validateAndDeriveMandateHash(
            mandate, adjustment.adjuster, adjustment, fillBlock, fillHashes
        );

        // Derive fill and claim amounts.
        {
            uint256 scalingMultiplier;
            (fillAmounts, claimAmounts, scalingMultiplier) = _deriveAmountsFromComponentsWithScaling(
                compact.commitments, mandate, adjustment, fillBlock
            );

            // Derive and check claim hash.
            claimHash = deriveClaimHash(compact, mandateHash);
            if (_dispositions[claimHash] != bytes32(0)) {
                revert AlreadyFilled();
            }

            // Set the disposition for the given claim hash.
            _dispositions[claimHash] = claimant;

            // Store the claim reduction scaling factor if claims were reduced.
            if (scalingMultiplier < BASE_SCALING_FACTOR) {
                _claimReductionScalingFactors[claimHash] = scalingMultiplier;
            }
        }

        // Verify adjuster authorization.
        if (!adjustment.adjuster
                .isValidSignatureNow(
                    _toAdjustmentHash(adjustment, claimHash).withDomain(_domainSeparator()),
                    adjustment.adjustmentAuthorization
                )) {
            revert InvalidAdjustment();
        }

        // Transfer fill tokens to recipients.
        _processFill(mandate, fillAmounts);

        // Build FillRecipient array for event.
        FillRecipient[] memory fillRecipients = new FillRecipient[](mandate.components.length);
        for (uint256 i = 0; i < mandate.components.length; i++) {
            fillRecipients[i] = FillRecipient({
                fillAmount: fillAmounts[i], recipient: mandate.components[i].recipient
            });
        }

        // Emit the fill event.
        emit Fill(
            compact.sponsor,
            claimant,
            claimHash,
            fillRecipients,
            claimAmounts,
            adjustment.targetBlock
        );

        // Perform recipient callback if specified.
        performRecipientCallback(mandate, claimHash, mandateHash, fillAmounts);
    }

    /**
     * @notice Internal implementation of atomic same-chain fill with a preceding claim execution.
     * @dev This function operates atomically in a single transaction, unlike the asynchronous nature of standard fills.
     * It optimistically releases input tokens to the filler first via a callback, then verifies they provided the output.
     * The filler receives a callback while holding the input tokens, allowing them to use those tokens to generate
     * the required output (flash loan-style). All output tokens must be provided to Tribunal upon exiting the callback.
     * Only supported when the claim chain and fill chain are the same.
     * @param claim The compact parameters including signatures.
     * @param mandate The fill conditions and amount derivation parameters.
     * @param adjustment The adjustment provided by the adjuster for the fill (includes adjuster and authorization).
     * @param claimant The recipient of claimed tokens on the claim chain (lock tag ++ address).
     * @param fillBlock The block number to target for the fill (must be current block).
     * @param fillHashes An array of the hashes of each fill in the mandate.
     * @return claimHash The derived claim hash.
     * @return mandateHash The derived mandate hash.
     * @return fillAmounts The amounts of tokens to be filled for each component.
     * @return claimAmounts The amounts of each token to be claimed.
     */
    function _claimAndFill(
        BatchClaim calldata claim,
        FillParameters calldata mandate,
        Adjustment calldata adjustment,
        bytes32 claimant,
        uint256 fillBlock,
        bytes32[] calldata fillHashes
    )
        internal
        returns (
            bytes32 claimHash,
            bytes32 mandateHash,
            uint256[] memory fillAmounts,
            uint256[] memory claimAmounts
        )
    {
        // Validate fill conditions and derive mandate hash.
        mandateHash = _validateAndDeriveMandateHash(
            mandate, adjustment.adjuster, adjustment, fillBlock, fillHashes
        );

        {
            // Derive fill and claim amounts.
            uint256 scalingMultiplier;
            (fillAmounts, claimAmounts, scalingMultiplier) = _deriveAmountsFromComponentsWithScaling(
                claim.compact.commitments, mandate, adjustment, fillBlock
            );

            // Execute the claim against The Compact and perform callback to filler.
            claimHash = _processClaimAndCallback(
                claim, mandate, mandateHash, fillAmounts, claimant, claimAmounts
            );

            // Store the claim reduction scaling factor if claims were reduced.
            if (scalingMultiplier < BASE_SCALING_FACTOR) {
                _claimReductionScalingFactors[claimHash] = scalingMultiplier;
            }
        }

        // Verify adjuster authorization.
        if (!adjustment.adjuster
                .isValidSignatureNow(
                    _toAdjustmentHash(adjustment, claimHash).withDomain(_domainSeparator()),
                    adjustment.adjustmentAuthorization
                )) {
            revert InvalidAdjustment();
        }

        // Transfer fill tokens to recipients.
        _processFill(mandate, fillAmounts);

        // Build FillRecipient array for event.
        FillRecipient[] memory fillRecipients = new FillRecipient[](mandate.components.length);
        for (uint256 i = 0; i < mandate.components.length; i++) {
            fillRecipients[i] = FillRecipient({
                fillAmount: fillAmounts[i], recipient: mandate.components[i].recipient
            });
        }

        // Emit the fill event.
        emit FillWithClaim(
            claim.compact.sponsor,
            claimant,
            claimHash,
            fillRecipients,
            claimAmounts,
            adjustment.targetBlock
        );

        // Perform recipient callback if specified.
        performRecipientCallback(mandate, claimHash, mandateHash, fillAmounts);
    }

    /**
     * @notice Triggers the recipient callback if one is specified in the mandate.
     * @dev The recipient callback is signed by the sponsor as part of the mandate and executes
     * automatically after fill token transfers are complete. It calls the first fill component's
     * recipient address and must succeed and return the intended magic value (this function selector)
     * for the fill to complete. Typically used for bridging fill tokens to destination chains or
     * registering follow-up compacts.
     * @param mandate The fill parameters containing the recipient callback specification.
     * @param claimHash The hash of the claim being filled.
     * @param mandateHash The hash of the mandate being executed.
     * @param fillAmounts The amounts of tokens being filled for each component.
     */
    function performRecipientCallback(
        FillParameters calldata mandate,
        bytes32 claimHash,
        bytes32 mandateHash,
        uint256[] memory fillAmounts
    ) internal {
        if (mandate.recipientCallback.length != 0 && mandate.components.length > 0) {
            RecipientCallback calldata callback = mandate.recipientCallback[0];
            // Use the first component for callback.
            FillComponent calldata component = mandate.components[0];
            if (
                IRecipientCallback(component.recipient)
                        .tribunalCallback(
                            callback.chainId,
                            claimHash,
                            mandateHash,
                            component.fillToken,
                            fillAmounts[0],
                            callback.compact,
                            callback.mandateHash,
                            callback.context
                        ) != IRecipientCallback.tribunalCallback.selector
            ) {
                revert InvalidRecipientCallback();
            }
        }
    }

    /**
     * @notice Processes the claim through The Compact and triggers the tribunal callback to the filler.
     * @dev This function constructs a batch claim, processes it through either the arbiter or The Compact
     * directly when Tribunal is the arbiter, then triggers a callback to the filler (msg.sender) with fill
     * requirements. The filler receives input tokens during the callback and must provide output tokens
     * before it completes. This enables flash loan-style operations where the filler uses claimed tokens
     * to generate required outputs.
     * @param batchClaim The batch claim containing compact parameters and signatures.
     * @param mandate The fill parameters with components and requirements.
     * @param mandateHash The hash of the mandate being executed.
     * @param fillAmounts The amounts to be filled for each component.
     * @param claimant The claimant identifier (lock tag ++ address).
     * @param claimAmounts The amounts to be claimed.
     * @return claimHash The hash of the processed claim.
     */
    function _processClaimAndCallback(
        BatchClaim calldata batchClaim,
        FillParameters calldata mandate,
        bytes32 mandateHash,
        uint256[] memory fillAmounts,
        bytes32 claimant,
        uint256[] memory claimAmounts
    ) internal returns (bytes32 claimHash) {
        // Extract compact parameters and signatures from the batch claim.
        BatchCompact calldata compact = batchClaim.compact;
        bytes calldata sponsorSignature = batchClaim.sponsorSignature;
        bytes calldata allocatorSignature = batchClaim.allocatorSignature;

        // Initialize claim structures.
        CompactBatchClaim memory claim;
        BatchClaimComponent memory component;

        {
            // Populate the batch claim structure with signatures and compact data.
            claim.allocatorData = allocatorSignature;
            claim.sponsorSignature = sponsorSignature;
            claim.sponsor = compact.sponsor;
            claim.nonce = compact.nonce;
            claim.expires = compact.expires;
            claim.witness = mandateHash;
            claim.witnessTypestring = WITNESS_TYPESTRING;

            // Build array of claim components with portions for each commitment.
            claim.claims = new BatchClaimComponent[](claimAmounts.length);
            for (uint256 i = 0; i < claimAmounts.length; i++) {
                // Construct the resource lock id from lock tag and token address.
                component.id = uint256(bytes32(compact.commitments[i].lockTag))
                    | uint256(uint160(compact.commitments[i].token));

                // Set the allocated amount from the commitment.
                component.allocatedAmount = compact.commitments[i].amount;

                // Create a single portion assigning the claim amount to the claimant.
                component.portions = new Component[](1);
                component.portions[0].claimant = uint256(claimant);
                component.portions[0].amount = claimAmounts[i];

                // Store the component in the claims array.
                claim.claims[i] = component;
            }

            // Determine the target for the claim: the arbiter or The Compact.
            address target = compact.arbiter;
            if (target == address(this)) {
                // If Tribunal is the arbiter, call The Compact directly.
                target = address(THE_COMPACT);
            }

            // Execute the batch claim and receive the claim hash.
            claimHash = ITheCompactClaims(target).batchClaim(claim);
        }

        // Trigger callback to the filler with fill requirements if components exist.
        if (mandate.components.length > 0) {
            // Construct array of fill requirements for the callback.
            FillRequirement[] memory fillRequirements =
                new FillRequirement[](mandate.components.length);
            for (uint256 i = 0; i < mandate.components.length; i++) {
                FillComponent memory fillComponent = mandate.components[i];

                // Populate each requirement with token, minimum, and realized amounts.
                fillRequirements[i] = FillRequirement({
                    fillToken: fillComponent.fillToken,
                    minimumFillAmount: fillComponent.minimumFillAmount,
                    realizedFillAmount: fillAmounts[i]
                });
            }

            // Call filler's callback with commitments and requirements.
            ITribunalCallback(msg.sender)
                .tribunalCallback(claimHash, compact.commitments, claimAmounts, fillRequirements);
        }

        return claimHash;
    }

    /**
     * @notice Internal function to cancel an unfilled auction.
     * @dev Verifies the caller is the sponsor, derives the claim hash, ensures the claim hasn't been filled,
     * marks it as cancelled by storing the sponsor as the claimant, stores type(uint256).max as the cancellation
     * flag in the scaling factors mapping, and emits a Cancel event. This prevents other fillers from executing
     * the auction on the target chain.
     * @param compact The compact parameters.
     * @param mandateHash The hash of the mandate to cancel.
     * @return claimHash The hash of the cancelled claim.
     */
    function _cancel(BatchCompact calldata compact, bytes32 mandateHash)
        internal
        returns (bytes32 claimHash)
    {
        // Ensure the claim can only be canceled by the sponsor.
        if (msg.sender != compact.sponsor) {
            revert NotSponsor();
        }

        // Derive and check claim hash.
        claimHash = deriveClaimHash(compact, mandateHash);
        if (_dispositions[claimHash] != bytes32(0)) {
            revert AlreadyFilled();
        }

        // Mark as cancelled by storing sponsor address in dispositions.
        _dispositions[claimHash] = bytes32(uint256(uint160(msg.sender)));

        // Store type(uint256).max as a sentinel value indicating cancellation.
        _claimReductionScalingFactors[claimHash] = type(uint256).max;

        // Emit the cancel event.
        emit Cancel(compact.sponsor, claimHash);

        return claimHash;
    }

    /**
     * @notice Transfers fill tokens from the filler to recipients for each component.
     * @dev Handles both native tokens (ETH) and ERC20 tokens. For native tokens, transfers directly
     * using safeTransferETH. For ERC20 tokens, uses safeTransferFrom from msg.sender to the recipient.
     * NOTE: Settling fee-on-transfer tokens will result in fewer tokens being received by the recipient.
     * Fillers must account for transfer fees when providing the desired fill amount.
     * @param mandate The fill parameters containing components with recipients and token addresses.
     * @param fillAmounts The amounts to transfer for each component.
     */
    function _processFill(FillParameters calldata mandate, uint256[] memory fillAmounts) internal {
        // Process each fill component.
        for (uint256 i = 0; i < mandate.components.length; i++) {
            FillComponent calldata component = mandate.components[i];
            uint256 componentAmount = fillAmounts[i];

            // Handle native token withdrawals directly.
            if (component.fillToken == address(0)) {
                component.recipient.safeTransferETH(componentAmount);
            } else {
                // NOTE: Settling fee-on-transfer tokens will result in fewer tokens
                // being received by the recipient. Be sure to accommodate for this when
                // providing the desired fill amount.
                component.fillToken
                    .safeTransferFrom(msg.sender, component.recipient, componentAmount);
            }
        }
    }

    /**
     * @notice Prepares ids and amounts array for compact operations.
     * @param commitment The commitment to prepare.
     * @return idsAndAmounts The prepared ids and amounts array.
     * @return callValue The value to send with the call.
     */
    function _prepareIdsAndAmounts(Lock calldata commitment)
        internal
        returns (uint256[2][] memory idsAndAmounts, uint256 callValue)
    {
        // Initialize array to hold id and amount pair.
        idsAndAmounts = new uint256[2][](1);
        callValue = 0;

        // Assign initial id using lock tag and token address.
        idsAndAmounts[0][0] =
            uint256(bytes32(commitment.lockTag)) | uint256(uint160(commitment.token));

        if (commitment.token == address(0)) {
            // Use full balance for native tokens and set as call value.
            callValue = address(this).balance;
            idsAndAmounts[0][1] = callValue;
        } else {
            // Query ERC20 balance held by this contract.
            idsAndAmounts[0][1] = commitment.token.balanceOf(address(this));

            // Check if allowance needs to be increased for The Compact.
            if (_checkCompactAllowance(commitment.token, address(this)) < idsAndAmounts[0][1]) {
                // Grant maximum approval to The Compact for future operations.
                SafeTransferLib.safeApproveWithRetry(
                    commitment.token, address(THE_COMPACT), type(uint256).max
                );
            }
        }

        return (idsAndAmounts, callValue);
    }

    /**
     * @notice Handles transferring tokens to a claimant. Transfers the full
     * available balance of the token named in the commitment.
     * @param commitment The commitment to transfer.
     * @param claimant The claimant to transfer to.
     */
    function _handleClaimantTransfer(Lock calldata commitment, bytes32 claimant) internal {
        if (commitment.token == address(0)) {
            // Extract address from lower 160 bits of claimant and transfer all native tokens.
            SafeTransferLib.safeTransferETH(
                address(uint160(uint256(claimant))), address(this).balance
            );
        } else {
            // Extract address from lower 160 bits of claimant and transfer all ERC20 tokens.
            commitment.token.safeTransferAll(address(uint160(uint256(claimant))));
        }
    }

    /**
     * @notice Handles direct transfer without lock tags.
     * @param commitment The commitment to transfer.
     * @param recipient The recipient address.
     */
    function _handleDirectTransfer(Lock calldata commitment, address recipient) internal {
        if (commitment.token == address(0)) {
            // Transfer all native tokens to the recipient.
            SafeTransferLib.safeTransferETH(recipient, address(this).balance);
        } else {
            // Transfer all ERC20 tokens to the recipient.
            commitment.token.safeTransferAll(recipient);
        }
    }

    /**
     * @notice Handles on-chain allocation registration.
     * @param compact The compact parameters.
     * @param idsAndAmounts The ids and amounts array.
     * @param callValue The value to send with the call.
     * @param mandateHash The mandate hash.
     * @param context The context data.
     * @return registeredClaimHash The registered claim hash.
     */
    function _handleOnChainAllocation(
        BatchCompact calldata compact,
        uint256[2][] memory idsAndAmounts,
        uint256 callValue,
        bytes32 mandateHash,
        bytes calldata context
    ) internal returns (bytes32 registeredClaimHash) {
        // Retrieve the allocator address for the resource lock.
        (, address allocator,,,) = THE_COMPACT.getLockDetails(idsAndAmounts[0][0]);

        // Request allocation preparation and receive a nonce from the allocator.
        (uint256 nonce) = IOnChainAllocation(allocator)
            .prepareAllocation(
                compact.sponsor,
                idsAndAmounts,
                compact.arbiter,
                compact.expires,
                COMPACT_TYPEHASH_WITH_MANDATE,
                mandateHash,
                context
            );

        // Deposit tokens to The Compact and register a compact with the nonce.
        (registeredClaimHash,) = THE_COMPACT.batchDepositAndRegisterFor{
            value: callValue
        }(
            compact.sponsor,
            idsAndAmounts,
            compact.arbiter,
            nonce,
            compact.expires,
            COMPACT_TYPEHASH_WITH_MANDATE,
            mandateHash
        );

        // Execute the allocation on the allocator to finalize the allocation.
        IOnChainAllocation(allocator)
            .executeAllocation(
                compact.sponsor,
                idsAndAmounts,
                compact.arbiter,
                compact.expires,
                COMPACT_TYPEHASH_WITH_MANDATE,
                mandateHash,
                context
            );

        return registeredClaimHash;
    }

    /**
     * @notice Handles direct registration without on-chain allocation.
     * @param compact The compact parameters.
     * @param idsAndAmounts The ids and amounts array.
     * @param callValue The value to send with the call.
     * @param mandateHash The mandate hash.
     * @return registeredClaimHash The registered claim hash.
     */
    function _handleDirectRegistration(
        BatchCompact calldata compact,
        uint256[2][] memory idsAndAmounts,
        uint256 callValue,
        bytes32 mandateHash
    ) internal returns (bytes32 registeredClaimHash) {
        // Deposit tokens and register the associated compact.
        (registeredClaimHash,) = THE_COMPACT.batchDepositAndRegisterFor{
            value: callValue
        }(
            compact.sponsor,
            idsAndAmounts,
            compact.arbiter,
            compact.nonce,
            compact.expires,
            COMPACT_TYPEHASH_WITH_MANDATE,
            mandateHash
        );

        return registeredClaimHash;
    }

    /**
     * @notice Internal function to perform a dispatch callback.
     * @param compact The compact parameters.
     * @param mandateHash The mandate hash.
     * @param claimHash The hash of the claim.
     * @param claimant The claimant bytes32 value.
     * @param claimAmounts The claim amounts.
     * @param dispatchParams The dispatch parameters.
     */
    function _performDispatchCallback(
        BatchCompact calldata compact,
        bytes32 mandateHash,
        bytes32 claimHash,
        bytes32 claimant,
        uint256[] memory claimAmounts,
        DispatchParameters calldata dispatchParams
    ) internal {
        uint256 scalingFactor = _getClaimReductionScalingFactor(claimHash);

        if (
            IDispatchCallback(dispatchParams.target)
                .dispatchCallback{
                    value: dispatchParams.value
                }(
                    dispatchParams.chainId,
                    compact,
                    mandateHash,
                    claimHash,
                    claimant,
                    scalingFactor,
                    claimAmounts,
                    dispatchParams.context
                ) != IDispatchCallback.dispatchCallback.selector
        ) {
            revert InvalidDispatchCallback();
        }

        emit Dispatch(dispatchParams.target, dispatchParams.chainId, claimant, claimHash);

        // Return any unused native tokens to the caller.
        uint256 remaining = address(this).balance;
        if (remaining > 0) {
            msg.sender.safeTransferETH(remaining);
        }
    }

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

    /**
     * @notice Validates the fill block parameter against the current block.
     * @param fillBlock The fill block parameter (0 allows current block).
     * @return normalizedFillBlock The normalized fill block (current block if input was 0).
     */
    function _validateFillBlock(uint256 fillBlock)
        internal
        view
        returns (uint256 normalizedFillBlock)
    {
        uint256 currentBlock = _getBlockNumberish();

        // If fillBlock is 0, replace it with currentBlock.
        assembly ("memory-safe") {
            // Utilize branchless logic to set currentBlock when no fillBlock is provided.
            normalizedFillBlock := xor(fillBlock, mul(iszero(fillBlock), currentBlock))
        }

        if (normalizedFillBlock != currentBlock) {
            revert InvalidFillBlock();
        }
    }

    /**
     * @notice Validates fill conditions (expiration, chainId, & adjustment) and derives the mandate hash.
     * @param mandate The fill mandate.
     * @param adjuster The assigned adjuster for the fill.
     * @param adjustment The adjustment parameters.
     * @param fillBlock The block number for the fill.
     * @param fillHashes An array of the hashes of each fill.
     * @return mandateHash The derived mandate hash.
     */
    function _validateAndDeriveMandateHash(
        FillParameters calldata mandate,
        address adjuster,
        Adjustment calldata adjustment,
        uint256 fillBlock,
        bytes32[] calldata fillHashes
    ) internal view returns (bytes32 mandateHash) {
        // Ensure that the mandate has not expired.
        mandate.expires.later();

        // Ensure correct chainId.
        if (mandate.chainId != block.chainid) {
            revert InvalidChainId();
        }

        // Extract filler address from lower 160 bits of validityConditions.
        address validFiller = address(uint160(uint256(adjustment.validityConditions)));
        // If validFiller is 0, default to msg.sender.
        assembly ("memory-safe") {
            // Use branchless logic to set caller if no filler is provided.
            validFiller := xor(validFiller, mul(iszero(validFiller), caller()))
        }

        // Extract block window from upper 96 bits of validityConditions.
        uint256 validBlockWindow = uint256(adjustment.validityConditions) >> _ADDRESS_BITS;

        // A validBlockWindow of 0 means no window restriction (valid indefinitely).
        // A validBlockWindow of 1 means it must be filled on the target block.
        if (((validBlockWindow != 0).and(adjustment.targetBlock + validBlockWindow <= fillBlock))
            .or(validFiller != msg.sender)) {
            revert ValidityConditionsNotMet();
        }

        // Derive mandate hash.
        mandateHash = _deriveMandateHash(mandate, adjuster, adjustment.fillIndex, fillHashes);
    }

    /**
     * @notice Internal function that derives amounts from components and returns the scaling multiplier.
     * @param maximumClaimAmounts The maximum amounts to claim.
     * @param mandate The fill parameters containing components and scaling info.
     * @param adjustment The adjustment parameters containing target block and supplemental price curve.
     * @param fillBlock The fill block number.
     * @return fillAmounts The derived fill amounts for each component.
     * @return claimAmounts The derived claim amounts.
     * @return scalingMultiplier The calculated scaling multiplier.
     */
    function _deriveAmountsFromComponentsWithScaling(
        Lock[] calldata maximumClaimAmounts,
        FillParameters calldata mandate,
        Adjustment calldata adjustment,
        uint256 fillBlock
    )
        internal
        view
        returns (
            uint256[] memory fillAmounts,
            uint256[] memory claimAmounts,
            uint256 scalingMultiplier
        )
    {
        uint256 baselinePriorityFee = mandate.baselinePriorityFee;
        uint256 scalingFactor = mandate.scalingFactor;

        // Apply supplemental price curve to mandate price curve.
        uint256[] memory priceCurve =
            mandate.priceCurve.applySupplementalPriceCurve(adjustment.supplementalPriceCurve);
        uint256 targetBlock = adjustment.targetBlock;

        // Calculate the current scaling factor from price curve.
        uint256 currentScalingFactor =
            _calculateCurrentScalingFactor(priceCurve, targetBlock, fillBlock);

        // Validate scaling direction.
        if (!scalingFactor.sharesScalingDirection(currentScalingFactor)) {
            revert PriceCurveLib.InvalidPriceCurveParameters();
        }

        // Calculate scaling multiplier and determine mode.
        bool useExactIn;
        (scalingMultiplier, useExactIn) =
            _calculateScalingMultiplier(currentScalingFactor, scalingFactor, baselinePriorityFee);

        // Calculate fill amounts.
        fillAmounts = _calculateFillAmounts(mandate.components, scalingMultiplier, useExactIn);

        // Calculate claim amounts.
        claimAmounts = _calculateClaimAmounts(maximumClaimAmounts, scalingMultiplier, useExactIn);

        return (fillAmounts, claimAmounts, scalingMultiplier);
    }

    /**
     * @notice Derives the mandate hash from an adjuster, a target fill, an array of fill hashes,
     * and the index of the target fill in the array.
     * @param targetFill The fill being executed.
     * @param adjuster The adjuster address.
     * @param fillIndex The index of the target fill in the fillHashes array.
     * @param fillHashes The array of fill hashes.
     * @return The derived mandate hash.
     */
    function _deriveMandateHash(
        FillParameters calldata targetFill,
        address adjuster,
        uint256 fillIndex,
        bytes32[] calldata fillHashes
    ) internal view returns (bytes32) {
        if (fillIndex >= fillHashes.length || fillHashes[fillIndex] != deriveFillHash(targetFill)) {
            revert InvalidFillHashArguments();
        }

        return
            keccak256(
                abi.encode(MANDATE_TYPEHASH, adjuster, keccak256(abi.encodePacked(fillHashes)))
            );
    }

    /**
     * @notice Checks the current token allowance granted to The Compact contract.
     * @dev Calls the ERC20 allowance function to check how many tokens the owner
     * has approved for The Compact to spend. Used to determine if additional approval
     * is needed before depositing tokens.
     * @param token The ERC20 token address to check allowance for.
     * @param owner The address whose allowance to check.
     * @return amount The current allowance amount, or 0 if the call fails.
     */
    function _checkCompactAllowance(address token, address owner)
        internal
        view
        returns (uint256 amount)
    {
        address compact = address(THE_COMPACT);
        assembly ("memory-safe") {
            mstore(0x14, owner) // Store the `owner` argument.
            mstore(0x34, compact)
            mstore(0x00, 0xdd62ed3e000000000000000000000000) // `allowance(address,address)`.
            amount := mul( // The arguments of `mul` are evaluated from right to left.
                mload(0x20),
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x10, 0x44, 0x20, 0x20)
                )
            )
            mstore(0x34, 0)
        }
    }

    /**
     * @notice Internal view function that returns the current EIP-712 domain separator,
     * updating it if the chain ID has changed since deployment.
     * @return The current domain separator.
     */
    function _domainSeparator() internal view returns (bytes32) {
        return _INITIAL_DOMAIN_SEPARATOR.toLatest(_INITIAL_CHAIN_ID);
    }

    /**
     * @notice Calculates the priority fee above the baseline for competitive pricing.
     * @dev The baseline represents the threshold where competitive scaling begins. Any priority fee below
     * this baseline has no effect on pricing. This is a core component of Priority Gas Auctions (PGA).
     * @param baselinePriorityFee The base fee threshold where scaling kicks in.
     * @return priorityFee The priority fee above baseline (or 0 if below).
     */
    function _getPriorityFee(uint256 baselinePriorityFee)
        internal
        view
        returns (uint256 priorityFee)
    {
        if (tx.gasprice < block.basefee) revert InvalidGasPrice();
        unchecked {
            // Calculate the priority fee paid by the transaction.
            priorityFee = tx.gasprice - block.basefee;

            // Only the amount above the baseline affects scaling factor.
            if (priorityFee > baselinePriorityFee) {
                priorityFee -= baselinePriorityFee;
            } else {
                priorityFee = 0;
            }
        }
    }

    /**
     * @notice Calculates the scaling multiplier due to priority fee and determines the auction mode (exact-in or exact-out).
     * @dev Exact-in mode (scalingFactor >= 1e18): fill amounts increase, claim amounts stay at maximum.
     * Exact-out mode (scalingFactor < 1e18): claim amounts decrease, fill amounts stay at minimum.
     * When neutral (scalingFactor == 1e18), mode is determined from currentScalingFactor.
     * @param currentScalingFactor The current scaling factor from price curve.
     * @param scalingFactor The scaling factor parameter from the mandate.
     * @param baselinePriorityFee The baseline priority fee.
     * @return scalingMultiplier The calculated scaling multiplier.
     * @return useExactIn Whether to use exact-in mode (true) or exact-out mode (false).
     */
    function _calculateScalingMultiplier(
        uint256 currentScalingFactor,
        uint256 scalingFactor,
        uint256 baselinePriorityFee
    ) internal view returns (uint256 scalingMultiplier, bool useExactIn) {
        uint256 priorityFeeAboveBaseline = _getPriorityFee(baselinePriorityFee);

        // Determine auction mode based on whether scaling factor is above or below 1e18.
        useExactIn = (scalingFactor > BASE_SCALING_FACTOR)
        .or(scalingFactor == BASE_SCALING_FACTOR && currentScalingFactor >= BASE_SCALING_FACTOR);

        if (useExactIn) {
            // Exact-in: add priority fee scaled by distance above 1e18.
            scalingMultiplier = currentScalingFactor
                + ((scalingFactor - BASE_SCALING_FACTOR) * priorityFeeAboveBaseline);
        } else {
            // Exact-out: subtract priority fee scaled by distance below 1e18.
            scalingMultiplier = currentScalingFactor
                - ((BASE_SCALING_FACTOR - scalingFactor) * priorityFeeAboveBaseline);
        }

        return (scalingMultiplier, useExactIn);
    }

    /**
     * @notice Internal view function to get the claim reduction scaling factor.
     * @param claimHash The hash of the claim.
     * @return scalingFactor The scaling factor (returns 1e18 if not set, 0 if cancelled).
     */
    function _getClaimReductionScalingFactor(bytes32 claimHash)
        internal
        view
        returns (uint256 scalingFactor)
    {
        uint256 storedScalingFactor = _claimReductionScalingFactors[claimHash];
        // Return 0 if cancelled (type(uint256).max sentinel), storedScalingFactor if set, else 1e18.
        assembly ("memory-safe") {
            // If storedScalingFactor is type(uint256).max, return 0 (cancelled)
            // Otherwise return storedScalingFactor if non-zero, else BASE_SCALING_FACTOR
            scalingFactor := mul(
                iszero(eq(storedScalingFactor, not(0))),
                or(storedScalingFactor, mul(iszero(storedScalingFactor), BASE_SCALING_FACTOR))
            )
        }
    }

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

    /**
     * @notice Calculates fill amounts for each component.
     * @param components The fill components.
     * @param scalingMultiplier The scaling multiplier.
     * @param useExactIn Whether to use exact-in mode.
     * @return fillAmounts The calculated fill amounts.
     */
    function _calculateFillAmounts(
        FillComponent[] calldata components,
        uint256 scalingMultiplier,
        bool useExactIn
    ) internal pure returns (uint256[] memory fillAmounts) {
        fillAmounts = new uint256[](components.length);
        for (uint256 i = 0; i < components.length; i++) {
            // Only scale components marked with applyScaling flag.
            if (components[i].applyScaling) {
                if (useExactIn) {
                    // In exact-in mode, scale up the fill amount.
                    fillAmounts[i] = components[i].minimumFillAmount.mulWadUp(scalingMultiplier);
                } else {
                    // In exact-out mode, use minimum unchanged.
                    fillAmounts[i] = components[i].minimumFillAmount;
                }
            } else {
                // Non-scaled components always use the minimum.
                fillAmounts[i] = components[i].minimumFillAmount;
            }
        }
        return fillAmounts;
    }

    /**
     * @notice Calculates claim amounts.
     * @param maximumClaimAmounts The maximum amounts to claim.
     * @param scalingMultiplier The scaling multiplier.
     * @param useExactIn Whether to use exact-in mode.
     * @return claimAmounts The calculated claim amounts.
     */
    function _calculateClaimAmounts(
        Lock[] calldata maximumClaimAmounts,
        uint256 scalingMultiplier,
        bool useExactIn
    ) internal pure returns (uint256[] memory claimAmounts) {
        claimAmounts = new uint256[](maximumClaimAmounts.length);
        if (useExactIn) {
            // In exact-in mode, use maximum claim amounts unchanged.
            for (uint256 i = 0; i < claimAmounts.length; i++) {
                claimAmounts[i] = maximumClaimAmounts[i].amount;
            }
        } else {
            // In exact-out mode, scale down the claim amounts.
            for (uint256 i = 0; i < claimAmounts.length; i++) {
                claimAmounts[i] = maximumClaimAmounts[i].amount.mulWad(scalingMultiplier);
            }
        }
        return claimAmounts;
    }

    /**
     * @notice Calculates the current scaling factor from the price curve based on blocks elapsed.
     * @dev Uses linear interpolation between discrete curve points to support gradual price transitions.
     * Zero-duration segments enable instant price jumps at specific blocks. If targetBlock is 0, no curve
     * is applied and the function returns the base scaling factor (1e18).
     * @param priceCurve The price curve to apply (array of duration/scaling-factor pairs).
     * @param targetBlock The auction start block number.
     * @param fillBlock The fill block number.
     * @return currentScalingFactor The calculated current scaling factor.
     */
    function _calculateCurrentScalingFactor(
        uint256[] memory priceCurve,
        uint256 targetBlock,
        uint256 fillBlock
    ) internal pure returns (uint256 currentScalingFactor) {
        currentScalingFactor = BASE_SCALING_FACTOR;
        if (targetBlock != 0) {
            if (targetBlock > fillBlock) {
                revert InvalidTargetBlock(fillBlock, targetBlock);
            }
            // Calculate blocks elapsed since auction start.
            uint256 blocksPassed;
            unchecked {
                blocksPassed = fillBlock - targetBlock;
            }

            // Apply price curve to determine scaling factor at current block.
            currentScalingFactor = priceCurve.getCalculatedValues(blocksPassed);
        } else {
            // Revert if no price curve has been provided.
            if (priceCurve.length != 0) {
                revert InvalidTargetBlockDesignation();
            }
        }
        return currentScalingFactor;
    }

    /**
     * @notice Derives the claim hash from compact and mandate hash based on a typehash.
     * @param compact The compact parameters.
     * @param mandateHash The derived mandate hash.
     * @param lockTypehash The lock typehash.
     * @param compactTypehash The compact typehash.
     * @return The claim hash.
     */
    function _deriveClaimHash(
        BatchCompact calldata compact,
        bytes32 mandateHash,
        bytes32 lockTypehash,
        bytes32 compactTypehash
    ) internal pure returns (bytes32) {
        bytes32 commitmentsHash = _deriveCommitmentsHash(compact.commitments, lockTypehash);
        return keccak256(
            abi.encode(
                compactTypehash,
                compact.arbiter,
                compact.sponsor,
                compact.nonce,
                compact.expires,
                commitmentsHash,
                mandateHash
            )
        );
    }

    /**
     * @notice Derives the hash of an array of commitments (locks) using EIP-712 typed data hashing.
     * @dev Each commitment is hashed individually using the provided typehash, then the array of
     * hashes is concatenated and hashed together.
     * @param commitments The array of locks (commitments) to hash.
     * @param typehash The EIP-712 typehash to use for each commitment.
     * @return The hash of the commitments array.
     */
    function _deriveCommitmentsHash(Lock[] calldata commitments, bytes32 typehash)
        internal
        pure
        returns (bytes32)
    {
        bytes32[] memory commitmentsHashes = new bytes32[](commitments.length);
        // Hash each commitment individually using EIP-712.
        for (uint256 i = 0; i < commitments.length; i++) {
            commitmentsHashes[i] = keccak256(
                abi.encode(
                    typehash, commitments[i].lockTag, commitments[i].token, commitments[i].amount
                )
            );
        }

        // Concatenate and hash all commitment hashes together.
        return keccak256(abi.encodePacked(commitmentsHashes));
    }

    /**
     * @notice Derives the EIP-712 hash of an adjustment for signature verification.
     * @dev Constructs the adjustment hash using the ADJUSTMENT_TYPEHASH and all adjustment parameters
     * including the claim hash, fill index, target block, supplemental price curve hash, and validity
     * conditions. This hash is used along with the current domain separator of this contract to verify
     * the adjuster's signature on the adjustment.
     * @param adjustment The adjustment parameters from the adjuster.
     * @param claimHash The hash of the claim being filled.
     * @return adjustmentHash The EIP-712 hash of the adjustment.
     */
    function _toAdjustmentHash(Adjustment calldata adjustment, bytes32 claimHash)
        internal
        pure
        returns (bytes32 adjustmentHash)
    {
        return keccak256(
            abi.encode(
                ADJUSTMENT_TYPEHASH,
                claimHash,
                adjustment.fillIndex,
                adjustment.targetBlock,
                keccak256(abi.encodePacked(adjustment.supplementalPriceCurve)),
                adjustment.validityConditions
            )
        );
    }
}

File 2 of 41 : LibBytes.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Library for byte related operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBytes.sol)
library LibBytes {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STRUCTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Goated bytes storage struct that totally MOGs, no cap, fr.
    /// Uses less gas and bytecode than Solidity's native bytes storage. It's meta af.
    /// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight.
    struct BytesStorage {
        bytes32 _spacer;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The constant returned when the `search` is not found in the bytes.
    uint256 internal constant NOT_FOUND = type(uint256).max;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  BYTE STORAGE OPERATIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Sets the value of the bytes storage `$` to `s`.
    function set(BytesStorage storage $, bytes memory s) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(s)
            let packed := or(0xff, shl(8, n))
            for { let i := 0 } 1 {} {
                if iszero(gt(n, 0xfe)) {
                    i := 0x1f
                    packed := or(n, shl(8, mload(add(s, i))))
                    if iszero(gt(n, i)) { break }
                }
                let o := add(s, 0x20)
                mstore(0x00, $.slot)
                for { let p := keccak256(0x00, 0x20) } 1 {} {
                    sstore(add(p, shr(5, i)), mload(add(o, i)))
                    i := add(i, 0x20)
                    if iszero(lt(i, n)) { break }
                }
                break
            }
            sstore($.slot, packed)
        }
    }

    /// @dev Sets the value of the bytes storage `$` to `s`.
    function setCalldata(BytesStorage storage $, bytes calldata s) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let packed := or(0xff, shl(8, s.length))
            for { let i := 0 } 1 {} {
                if iszero(gt(s.length, 0xfe)) {
                    i := 0x1f
                    packed := or(s.length, shl(8, shr(8, calldataload(s.offset))))
                    if iszero(gt(s.length, i)) { break }
                }
                mstore(0x00, $.slot)
                for { let p := keccak256(0x00, 0x20) } 1 {} {
                    sstore(add(p, shr(5, i)), calldataload(add(s.offset, i)))
                    i := add(i, 0x20)
                    if iszero(lt(i, s.length)) { break }
                }
                break
            }
            sstore($.slot, packed)
        }
    }

    /// @dev Sets the value of the bytes storage `$` to the empty bytes.
    function clear(BytesStorage storage $) internal {
        delete $._spacer;
    }

    /// @dev Returns whether the value stored is `$` is the empty bytes "".
    function isEmpty(BytesStorage storage $) internal view returns (bool) {
        return uint256($._spacer) & 0xff == uint256(0);
    }

    /// @dev Returns the length of the value stored in `$`.
    function length(BytesStorage storage $) internal view returns (uint256 result) {
        result = uint256($._spacer);
        /// @solidity memory-safe-assembly
        assembly {
            let n := and(0xff, result)
            result := or(mul(shr(8, result), eq(0xff, n)), mul(n, iszero(eq(0xff, n))))
        }
    }

    /// @dev Returns the value stored in `$`.
    function get(BytesStorage storage $) internal view returns (bytes memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            let o := add(result, 0x20)
            let packed := sload($.slot)
            let n := shr(8, packed)
            for { let i := 0 } 1 {} {
                if iszero(eq(or(packed, 0xff), packed)) {
                    mstore(o, packed)
                    n := and(0xff, packed)
                    i := 0x1f
                    if iszero(gt(n, i)) { break }
                }
                mstore(0x00, $.slot)
                for { let p := keccak256(0x00, 0x20) } 1 {} {
                    mstore(add(o, i), sload(add(p, shr(5, i))))
                    i := add(i, 0x20)
                    if iszero(lt(i, n)) { break }
                }
                break
            }
            mstore(result, n) // Store the length of the memory.
            mstore(add(o, n), 0) // Zeroize the slot after the bytes.
            mstore(0x40, add(add(o, n), 0x20)) // Allocate memory.
        }
    }

    /// @dev Returns the uint8 at index `i`. If out-of-bounds, returns 0.
    function uint8At(BytesStorage storage $, uint256 i) internal view returns (uint8 result) {
        /// @solidity memory-safe-assembly
        assembly {
            for { let packed := sload($.slot) } 1 {} {
                if iszero(eq(or(packed, 0xff), packed)) {
                    if iszero(gt(i, 0x1e)) {
                        result := byte(i, packed)
                        break
                    }
                    if iszero(gt(i, and(0xff, packed))) {
                        mstore(0x00, $.slot)
                        let j := sub(i, 0x1f)
                        result := byte(and(j, 0x1f), sload(add(keccak256(0x00, 0x20), shr(5, j))))
                    }
                    break
                }
                if iszero(gt(i, shr(8, packed))) {
                    mstore(0x00, $.slot)
                    result := byte(and(i, 0x1f), sload(add(keccak256(0x00, 0x20), shr(5, i))))
                }
                break
            }
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      BYTES OPERATIONS                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`.
    function replace(bytes memory subject, bytes memory needle, bytes memory replacement)
        internal
        pure
        returns (bytes memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            let needleLen := mload(needle)
            let replacementLen := mload(replacement)
            let d := sub(result, subject) // Memory difference.
            let i := add(subject, 0x20) // Subject bytes pointer.
            mstore(0x00, add(i, mload(subject))) // End of subject.
            if iszero(gt(needleLen, mload(subject))) {
                let subjectSearchEnd := add(sub(mload(0x00), needleLen), 1)
                let h := 0 // The hash of `needle`.
                if iszero(lt(needleLen, 0x20)) { h := keccak256(add(needle, 0x20), needleLen) }
                let s := mload(add(needle, 0x20))
                for { let m := shl(3, sub(0x20, and(needleLen, 0x1f))) } 1 {} {
                    let t := mload(i)
                    // Whether the first `needleLen % 32` bytes of `subject` and `needle` matches.
                    if iszero(shr(m, xor(t, s))) {
                        if h {
                            if iszero(eq(keccak256(i, needleLen), h)) {
                                mstore(add(i, d), t)
                                i := add(i, 1)
                                if iszero(lt(i, subjectSearchEnd)) { break }
                                continue
                            }
                        }
                        // Copy the `replacement` one word at a time.
                        for { let j := 0 } 1 {} {
                            mstore(add(add(i, d), j), mload(add(add(replacement, 0x20), j)))
                            j := add(j, 0x20)
                            if iszero(lt(j, replacementLen)) { break }
                        }
                        d := sub(add(d, replacementLen), needleLen)
                        if needleLen {
                            i := add(i, needleLen)
                            if iszero(lt(i, subjectSearchEnd)) { break }
                            continue
                        }
                    }
                    mstore(add(i, d), t)
                    i := add(i, 1)
                    if iszero(lt(i, subjectSearchEnd)) { break }
                }
            }
            let end := mload(0x00)
            let n := add(sub(d, add(result, 0x20)), end)
            // Copy the rest of the bytes one word at a time.
            for {} lt(i, end) { i := add(i, 0x20) } { mstore(add(i, d), mload(i)) }
            let o := add(i, d)
            mstore(o, 0) // Zeroize the slot after the bytes.
            mstore(0x40, add(o, 0x20)) // Allocate memory.
            mstore(result, n) // Store the length.
        }
    }

    /// @dev Returns the byte index of the first location of `needle` in `subject`,
    /// needleing from left to right, starting from `from`.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
    function indexOf(bytes memory subject, bytes memory needle, uint256 from)
        internal
        pure
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            result := not(0) // Initialize to `NOT_FOUND`.
            for { let subjectLen := mload(subject) } 1 {} {
                if iszero(mload(needle)) {
                    result := from
                    if iszero(gt(from, subjectLen)) { break }
                    result := subjectLen
                    break
                }
                let needleLen := mload(needle)
                let subjectStart := add(subject, 0x20)

                subject := add(subjectStart, from)
                let end := add(sub(add(subjectStart, subjectLen), needleLen), 1)
                let m := shl(3, sub(0x20, and(needleLen, 0x1f)))
                let s := mload(add(needle, 0x20))

                if iszero(and(lt(subject, end), lt(from, subjectLen))) { break }

                if iszero(lt(needleLen, 0x20)) {
                    for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} {
                        if iszero(shr(m, xor(mload(subject), s))) {
                            if eq(keccak256(subject, needleLen), h) {
                                result := sub(subject, subjectStart)
                                break
                            }
                        }
                        subject := add(subject, 1)
                        if iszero(lt(subject, end)) { break }
                    }
                    break
                }
                for {} 1 {} {
                    if iszero(shr(m, xor(mload(subject), s))) {
                        result := sub(subject, subjectStart)
                        break
                    }
                    subject := add(subject, 1)
                    if iszero(lt(subject, end)) { break }
                }
                break
            }
        }
    }

    /// @dev Returns the byte index of the first location of `needle` in `subject`,
    /// needleing from left to right, starting from `from`. Optimized for byte needles.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
    function indexOfByte(bytes memory subject, bytes1 needle, uint256 from)
        internal
        pure
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            result := not(0) // Initialize to `NOT_FOUND`.
            if gt(mload(subject), from) {
                let start := add(subject, 0x20)
                let end := add(start, mload(subject))
                let m := div(not(0), 255) // `0x0101 ... `.
                let h := mul(byte(0, needle), m) // Replicating needle mask.
                m := not(shl(7, m)) // `0x7f7f ... `.
                for { let i := add(start, from) } 1 {} {
                    let c := xor(mload(i), h) // Load 32-byte chunk and xor with mask.
                    c := not(or(or(add(and(c, m), m), c), m)) // Each needle byte will be `0x80`.
                    if c {
                        c := and(not(shr(shl(3, sub(end, i)), not(0))), c) // Truncate bytes past the end.
                        if c {
                            let r := shl(7, lt(0x8421084210842108cc6318c6db6d54be, c)) // Save bytecode.
                            r := or(shl(6, lt(0xffffffffffffffff, shr(r, c))), r)
                            // forgefmt: disable-next-item
                            result := add(sub(i, start), shr(3, xor(byte(and(0x1f, shr(byte(24,
                                mul(0x02040810204081, shr(r, c))), 0x8421084210842108cc6318c6db6d54be)),
                                0xc0c8c8d0c8e8d0d8c8e8e0e8d0d8e0f0c8d0e8d0e0e0d8f0d0d0e0d8f8f8f8f8), r)))
                            break
                        }
                    }
                    i := add(i, 0x20)
                    if iszero(lt(i, end)) { break }
                }
            }
        }
    }

    /// @dev Returns the byte index of the first location of `needle` in `subject`,
    /// needleing from left to right. Optimized for byte needles.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
    function indexOfByte(bytes memory subject, bytes1 needle)
        internal
        pure
        returns (uint256 result)
    {
        return indexOfByte(subject, needle, 0);
    }

    /// @dev Returns the byte index of the first location of `needle` in `subject`,
    /// needleing from left to right.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
    function indexOf(bytes memory subject, bytes memory needle) internal pure returns (uint256) {
        return indexOf(subject, needle, 0);
    }

    /// @dev Returns the byte index of the first location of `needle` in `subject`,
    /// needleing from right to left, starting from `from`.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
    function lastIndexOf(bytes memory subject, bytes memory needle, uint256 from)
        internal
        pure
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            for {} 1 {} {
                result := not(0) // Initialize to `NOT_FOUND`.
                let needleLen := mload(needle)
                if gt(needleLen, mload(subject)) { break }
                let w := result

                let fromMax := sub(mload(subject), needleLen)
                if iszero(gt(fromMax, from)) { from := fromMax }

                let end := add(add(subject, 0x20), w)
                subject := add(add(subject, 0x20), from)
                if iszero(gt(subject, end)) { break }
                // As this function is not too often used,
                // we shall simply use keccak256 for smaller bytecode size.
                for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} {
                    if eq(keccak256(subject, needleLen), h) {
                        result := sub(subject, add(end, 1))
                        break
                    }
                    subject := add(subject, w) // `sub(subject, 1)`.
                    if iszero(gt(subject, end)) { break }
                }
                break
            }
        }
    }

    /// @dev Returns the byte index of the first location of `needle` in `subject`,
    /// needleing from right to left.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
    function lastIndexOf(bytes memory subject, bytes memory needle)
        internal
        pure
        returns (uint256)
    {
        return lastIndexOf(subject, needle, type(uint256).max);
    }

    /// @dev Returns true if `needle` is found in `subject`, false otherwise.
    function contains(bytes memory subject, bytes memory needle) internal pure returns (bool) {
        return indexOf(subject, needle) != NOT_FOUND;
    }

    /// @dev Returns whether `subject` starts with `needle`.
    function startsWith(bytes memory subject, bytes memory needle)
        internal
        pure
        returns (bool result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(needle)
            // Just using keccak256 directly is actually cheaper.
            let t := eq(keccak256(add(subject, 0x20), n), keccak256(add(needle, 0x20), n))
            result := lt(gt(n, mload(subject)), t)
        }
    }

    /// @dev Returns whether `subject` ends with `needle`.
    function endsWith(bytes memory subject, bytes memory needle)
        internal
        pure
        returns (bool result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(needle)
            let notInRange := gt(n, mload(subject))
            // `subject + 0x20 + max(subject.length - needle.length, 0)`.
            let t := add(add(subject, 0x20), mul(iszero(notInRange), sub(mload(subject), n)))
            // Just using keccak256 directly is actually cheaper.
            result := gt(eq(keccak256(t, n), keccak256(add(needle, 0x20), n)), notInRange)
        }
    }

    /// @dev Returns `subject` repeated `times`.
    function repeat(bytes memory subject, uint256 times)
        internal
        pure
        returns (bytes memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let l := mload(subject) // Subject length.
            if iszero(or(iszero(times), iszero(l))) {
                result := mload(0x40)
                subject := add(subject, 0x20)
                let o := add(result, 0x20)
                for {} 1 {} {
                    // Copy the `subject` one word at a time.
                    for { let j := 0 } 1 {} {
                        mstore(add(o, j), mload(add(subject, j)))
                        j := add(j, 0x20)
                        if iszero(lt(j, l)) { break }
                    }
                    o := add(o, l)
                    times := sub(times, 1)
                    if iszero(times) { break }
                }
                mstore(o, 0) // Zeroize the slot after the bytes.
                mstore(0x40, add(o, 0x20)) // Allocate memory.
                mstore(result, sub(o, add(result, 0x20))) // Store the length.
            }
        }
    }

    /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
    /// `start` and `end` are byte offsets.
    function slice(bytes memory subject, uint256 start, uint256 end)
        internal
        pure
        returns (bytes memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let l := mload(subject) // Subject length.
            if iszero(gt(l, end)) { end := l }
            if iszero(gt(l, start)) { start := l }
            if lt(start, end) {
                result := mload(0x40)
                let n := sub(end, start)
                let i := add(subject, start)
                let w := not(0x1f)
                // Copy the `subject` one word at a time, backwards.
                for { let j := and(add(n, 0x1f), w) } 1 {} {
                    mstore(add(result, j), mload(add(i, j)))
                    j := add(j, w) // `sub(j, 0x20)`.
                    if iszero(j) { break }
                }
                let o := add(add(result, 0x20), n)
                mstore(o, 0) // Zeroize the slot after the bytes.
                mstore(0x40, add(o, 0x20)) // Allocate memory.
                mstore(result, n) // Store the length.
            }
        }
    }

    /// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes.
    /// `start` is a byte offset.
    function slice(bytes memory subject, uint256 start)
        internal
        pure
        returns (bytes memory result)
    {
        result = slice(subject, start, type(uint256).max);
    }

    /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
    /// `start` and `end` are byte offsets. Faster than Solidity's native slicing.
    function sliceCalldata(bytes calldata subject, uint256 start, uint256 end)
        internal
        pure
        returns (bytes calldata result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            end := xor(end, mul(xor(end, subject.length), lt(subject.length, end)))
            start := xor(start, mul(xor(start, subject.length), lt(subject.length, start)))
            result.offset := add(subject.offset, start)
            result.length := mul(lt(start, end), sub(end, start))
        }
    }

    /// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes.
    /// `start` is a byte offset. Faster than Solidity's native slicing.
    function sliceCalldata(bytes calldata subject, uint256 start)
        internal
        pure
        returns (bytes calldata result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            start := xor(start, mul(xor(start, subject.length), lt(subject.length, start)))
            result.offset := add(subject.offset, start)
            result.length := mul(lt(start, subject.length), sub(subject.length, start))
        }
    }

    /// @dev Reduces the size of `subject` to `n`.
    /// If `n` is greater than the size of `subject`, this will be a no-op.
    function truncate(bytes memory subject, uint256 n)
        internal
        pure
        returns (bytes memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            result := subject
            mstore(mul(lt(n, mload(result)), result), n)
        }
    }

    /// @dev Returns a copy of `subject`, with the length reduced to `n`.
    /// If `n` is greater than the size of `subject`, this will be a no-op.
    function truncatedCalldata(bytes calldata subject, uint256 n)
        internal
        pure
        returns (bytes calldata result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            result.offset := subject.offset
            result.length := xor(n, mul(xor(n, subject.length), lt(subject.length, n)))
        }
    }

    /// @dev Returns all the indices of `needle` in `subject`.
    /// The indices are byte offsets.
    function indicesOf(bytes memory subject, bytes memory needle)
        internal
        pure
        returns (uint256[] memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let searchLen := mload(needle)
            if iszero(gt(searchLen, mload(subject))) {
                result := mload(0x40)
                let i := add(subject, 0x20)
                let o := add(result, 0x20)
                let subjectSearchEnd := add(sub(add(i, mload(subject)), searchLen), 1)
                let h := 0 // The hash of `needle`.
                if iszero(lt(searchLen, 0x20)) { h := keccak256(add(needle, 0x20), searchLen) }
                let s := mload(add(needle, 0x20))
                for { let m := shl(3, sub(0x20, and(searchLen, 0x1f))) } 1 {} {
                    let t := mload(i)
                    // Whether the first `searchLen % 32` bytes of `subject` and `needle` matches.
                    if iszero(shr(m, xor(t, s))) {
                        if h {
                            if iszero(eq(keccak256(i, searchLen), h)) {
                                i := add(i, 1)
                                if iszero(lt(i, subjectSearchEnd)) { break }
                                continue
                            }
                        }
                        mstore(o, sub(i, add(subject, 0x20))) // Append to `result`.
                        o := add(o, 0x20)
                        i := add(i, searchLen) // Advance `i` by `searchLen`.
                        if searchLen {
                            if iszero(lt(i, subjectSearchEnd)) { break }
                            continue
                        }
                    }
                    i := add(i, 1)
                    if iszero(lt(i, subjectSearchEnd)) { break }
                }
                mstore(result, shr(5, sub(o, add(result, 0x20)))) // Store the length of `result`.
                // Allocate memory for result.
                // We allocate one more word, so this array can be recycled for {split}.
                mstore(0x40, add(o, 0x20))
            }
        }
    }

    /// @dev Returns an arrays of bytess based on the `delimiter` inside of the `subject` bytes.
    function split(bytes memory subject, bytes memory delimiter)
        internal
        pure
        returns (bytes[] memory result)
    {
        uint256[] memory indices = indicesOf(subject, delimiter);
        /// @solidity memory-safe-assembly
        assembly {
            let w := not(0x1f)
            let indexPtr := add(indices, 0x20)
            let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))
            mstore(add(indicesEnd, w), mload(subject))
            mstore(indices, add(mload(indices), 1))
            for { let prevIndex := 0 } 1 {} {
                let index := mload(indexPtr)
                mstore(indexPtr, 0x60)
                if iszero(eq(index, prevIndex)) {
                    let element := mload(0x40)
                    let l := sub(index, prevIndex)
                    mstore(element, l) // Store the length of the element.
                    // Copy the `subject` one word at a time, backwards.
                    for { let o := and(add(l, 0x1f), w) } 1 {} {
                        mstore(add(element, o), mload(add(add(subject, prevIndex), o)))
                        o := add(o, w) // `sub(o, 0x20)`.
                        if iszero(o) { break }
                    }
                    mstore(add(add(element, 0x20), l), 0) // Zeroize the slot after the bytes.
                    // Allocate memory for the length and the bytes, rounded up to a multiple of 32.
                    mstore(0x40, add(element, and(add(l, 0x3f), w)))
                    mstore(indexPtr, element) // Store the `element` into the array.
                }
                prevIndex := add(index, mload(delimiter))
                indexPtr := add(indexPtr, 0x20)
                if iszero(lt(indexPtr, indicesEnd)) { break }
            }
            result := indices
            if iszero(mload(delimiter)) {
                result := add(indices, 0x20)
                mstore(result, sub(mload(indices), 2))
            }
        }
    }

    /// @dev Returns a concatenated bytes of `a` and `b`.
    /// Cheaper than `bytes.concat()` and does not de-align the free memory pointer.
    function concat(bytes memory a, bytes memory b) internal pure returns (bytes memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40)
            let w := not(0x1f)
            let aLen := mload(a)
            // Copy `a` one word at a time, backwards.
            for { let o := and(add(aLen, 0x20), w) } 1 {} {
                mstore(add(result, o), mload(add(a, o)))
                o := add(o, w) // `sub(o, 0x20)`.
                if iszero(o) { break }
            }
            let bLen := mload(b)
            let output := add(result, aLen)
            // Copy `b` one word at a time, backwards.
            for { let o := and(add(bLen, 0x20), w) } 1 {} {
                mstore(add(output, o), mload(add(b, o)))
                o := add(o, w) // `sub(o, 0x20)`.
                if iszero(o) { break }
            }
            let totalLen := add(aLen, bLen)
            let last := add(add(result, 0x20), totalLen)
            mstore(last, 0) // Zeroize the slot after the bytes.
            mstore(result, totalLen) // Store the length.
            mstore(0x40, add(last, 0x20)) // Allocate memory.
        }
    }

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

    /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small bytes.
    function eqs(bytes memory a, bytes32 b) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            // These should be evaluated on compile time, as far as possible.
            let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.
            let x := not(or(m, or(b, add(m, and(b, m)))))
            let r := shl(7, iszero(iszero(shr(128, x))))
            r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            // forgefmt: disable-next-item
            result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),
                xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))
        }
    }

    /// @dev Returns 0 if `a == b`, -1 if `a < b`, +1 if `a > b`.
    /// If `a` == b[:a.length]`, and `a.length < b.length`, returns -1.
    function cmp(bytes memory a, bytes memory b) internal pure returns (int256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let aLen := mload(a)
            let bLen := mload(b)
            let n := and(xor(aLen, mul(xor(aLen, bLen), lt(bLen, aLen))), not(0x1f))
            if n {
                for { let i := 0x20 } 1 {} {
                    let x := mload(add(a, i))
                    let y := mload(add(b, i))
                    if iszero(or(xor(x, y), eq(i, n))) {
                        i := add(i, 0x20)
                        continue
                    }
                    result := sub(gt(x, y), lt(x, y))
                    break
                }
            }
            // forgefmt: disable-next-item
            if iszero(result) {
                let l := 0x201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201
                let x := and(mload(add(add(a, 0x20), n)), shl(shl(3, byte(sub(aLen, n), l)), not(0)))
                let y := and(mload(add(add(b, 0x20), n)), shl(shl(3, byte(sub(bLen, n), l)), not(0)))
                result := sub(gt(x, y), lt(x, y))
                if iszero(result) { result := sub(gt(aLen, bLen), lt(aLen, bLen)) }
            }
        }
    }

    /// @dev Directly returns `a` without copying.
    function directReturn(bytes memory a) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            // Assumes that the bytes does not start from the scratch space.
            let retStart := sub(a, 0x20)
            let retUnpaddedSize := add(mload(a), 0x40)
            // Right pad with zeroes. Just in case the bytes is produced
            // by a method that doesn't zero right pad.
            mstore(add(retStart, retUnpaddedSize), 0)
            mstore(retStart, 0x20) // Store the return offset.
            // End the transaction, returning the bytes.
            return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize)))
        }
    }

    /// @dev Directly returns `a` with minimal copying.
    function directReturn(bytes[] memory a) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(a) // `a.length`.
            let o := add(a, 0x20) // Start of elements in `a`.
            let u := a // Highest memory slot.
            let w := not(0x1f)
            for { let i := 0 } iszero(eq(i, n)) { i := add(i, 1) } {
                let c := add(o, shl(5, i)) // Location of pointer to `a[i]`.
                let s := mload(c) // `a[i]`.
                let l := mload(s) // `a[i].length`.
                let r := and(l, 0x1f) // `a[i].length % 32`.
                let z := add(0x20, and(l, w)) // Offset of last word in `a[i]` from `s`.
                // If `s` comes before `o`, or `s` is not zero right padded.
                if iszero(lt(lt(s, o), or(iszero(r), iszero(shl(shl(3, r), mload(add(s, z))))))) {
                    let m := mload(0x40)
                    mstore(m, l) // Copy `a[i].length`.
                    for {} 1 {} {
                        mstore(add(m, z), mload(add(s, z))) // Copy `a[i]`, backwards.
                        z := add(z, w) // `sub(z, 0x20)`.
                        if iszero(z) { break }
                    }
                    let e := add(add(m, 0x20), l)
                    mstore(e, 0) // Zeroize the slot after the copied bytes.
                    mstore(0x40, add(e, 0x20)) // Allocate memory.
                    s := m
                }
                mstore(c, sub(s, o)) // Convert to calldata offset.
                let t := add(l, add(s, 0x20))
                if iszero(lt(t, u)) { u := t }
            }
            let retStart := add(a, w) // Assumes `a` doesn't start from scratch space.
            mstore(retStart, 0x20) // Store the return offset.
            return(retStart, add(0x40, sub(u, retStart))) // End the transaction.
        }
    }

    /// @dev Returns the word at `offset`, without any bounds checks.
    function load(bytes memory a, uint256 offset) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(add(add(a, 0x20), offset))
        }
    }

    /// @dev Returns the word at `offset`, without any bounds checks.
    function loadCalldata(bytes calldata a, uint256 offset)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            result := calldataload(add(a.offset, offset))
        }
    }

    /// @dev Returns a slice representing a static struct in the calldata. Performs bounds checks.
    function staticStructInCalldata(bytes calldata a, uint256 offset)
        internal
        pure
        returns (bytes calldata result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let l := sub(a.length, 0x20)
            result.offset := add(a.offset, offset)
            result.length := sub(a.length, offset)
            if or(shr(64, or(l, a.offset)), gt(offset, l)) { revert(l, 0x00) }
        }
    }

    /// @dev Returns a slice representing a dynamic struct in the calldata. Performs bounds checks.
    function dynamicStructInCalldata(bytes calldata a, uint256 offset)
        internal
        pure
        returns (bytes calldata result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let l := sub(a.length, 0x20)
            let s := calldataload(add(a.offset, offset)) // Relative offset of `result` from `a.offset`.
            result.offset := add(a.offset, s)
            result.length := sub(a.length, s)
            if or(shr(64, or(s, or(l, a.offset))), gt(offset, l)) { revert(l, 0x00) }
        }
    }

    /// @dev Returns bytes in calldata. Performs bounds checks.
    function bytesInCalldata(bytes calldata a, uint256 offset)
        internal
        pure
        returns (bytes calldata result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let l := sub(a.length, 0x20)
            let s := calldataload(add(a.offset, offset)) // Relative offset of `result` from `a.offset`.
            result.offset := add(add(a.offset, s), 0x20)
            result.length := calldataload(add(a.offset, s))
            // forgefmt: disable-next-item
            if or(shr(64, or(result.length, or(s, or(l, a.offset)))),
                or(gt(add(s, result.length), l), gt(offset, l))) { revert(l, 0x00) }
        }
    }

    /// @dev Returns empty calldata bytes. For silencing the compiler.
    function emptyCalldata() internal pure returns (bytes calldata result) {
        /// @solidity memory-safe-assembly
        assembly {
            result.length := 0
        }
    }

    /// @dev Returns the most significant 20 bytes as an address.
    function msbToAddress(bytes32 x) internal pure returns (address) {
        return address(bytes20(x));
    }

    /// @dev Returns the least significant 20 bytes as an address.
    function lsbToAddress(bytes32 x) internal pure returns (address) {
        return address(uint160(uint256(x)));
    }
}

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

import { Scope } from "../types/Scope.sol";

import { IdLib } from "./IdLib.sol";
import { ConsumerLib } from "./ConsumerLib.sol";
import { EfficiencyLib } from "./EfficiencyLib.sol";
import { DomainLib } from "./DomainLib.sol";
import { EmissaryLib } from "./EmissaryLib.sol";
import { RegistrationLib } from "./RegistrationLib.sol";

import { SignatureCheckerLib } from "solady/utils/SignatureCheckerLib.sol";

/**
 * @title ValidityLib
 * @notice Library contract implementing logic for validating expirations,
 * signatures, nonces (including consuming unused nonces), and token addresses.
 */
library ValidityLib {
    using RegistrationLib for address;
    using ValidityLib for address;
    using IdLib for uint96;
    using IdLib for uint256;
    using ConsumerLib for uint256;
    using EfficiencyLib for bool;
    using DomainLib for bytes32;
    using EmissaryLib for bytes32;
    using EmissaryLib for uint256[2][];
    using SignatureCheckerLib for address;

    /**
     * @notice Internal function that retrieves an allocator's address from their ID and
     * consumes a nonce in their scope. Reverts if the allocator is not registered.
     * @param allocatorId The unique identifier for a registered allocator.
     * @param nonce       The nonce to consume in the allocator's scope.
     * @return allocator  The address of the registered allocator.
     */
    function fromRegisteredAllocatorIdWithConsumed(uint96 allocatorId, uint256 nonce)
        internal
        returns (address allocator)
    {
        allocator = allocatorId.toRegisteredAllocator();
        nonce.consumeNonceAsAllocator(allocator);
    }

    /**
     * @notice Internal view function that ensures that a timestamp has not yet passed.
     * Reverts if the provided timestamp is not in the future.
     * @param expires The timestamp to check.
     */
    function later(uint256 expires) internal view {
        assembly ("memory-safe") {
            if iszero(gt(expires, timestamp())) {
                // revert Expired(expiration);
                mstore(0, 0xf80dbaea)
                mstore(0x20, expires)
                revert(0x1c, 0x24)
            }
        }
    }

    /**
     * @notice Internal function that validates a signature against an expected signer.
     * Returns if the signature is valid or if the caller is the expected signer, otherwise
     * reverts. The message hash is combined with the domain separator before verification.
     * If ECDSA recovery fails, an EIP-1271 isValidSignature check is performed. Note that
     * an emissary check will not be performed.
     * @param messageHash     The EIP-712 hash of the message to verify.
     * @param expectedSigner  The address that should have signed the message.
     * @param signature       The signature to verify.
     * @param domainSeparator The domain separator to combine with the message hash.
     */
    function hasValidSponsor(
        bytes32 messageHash,
        address expectedSigner,
        bytes calldata signature,
        bytes32 domainSeparator
    ) internal view {
        // Apply domain separator to message hash to derive the digest.
        bytes32 digest = messageHash.withDomain(domainSeparator);

        // First, check signature against digest with ECDSA (or ensure sponsor is caller).
        if (expectedSigner.isValidECDSASignatureCalldata(digest, signature)) {
            return;
        }

        // Finally, check EIP1271 using the digest and signature.
        if (expectedSigner.isValidERC1271SignatureNowCalldata(digest, signature)) {
            return;
        }

        assembly ("memory-safe") {
            // revert InvalidSignature();
            mstore(0, 0x8baa579f)
            revert(0x1c, 0x04)
        }
    }

    /**
     * @notice Internal function that validates a signature or registration against an expected
     * signer. If the initial verification fails, the emissary is used to validate the claim.
     * Returns if the signature is valid or if the caller is the expected signer, otherwise
     * reverts. The claim hash is combined with the domain separator before verification.
     * If ECDSA recovery fails, an EIP-1271 isValidSignature check is performed with half of
     * available gas. If EIP-1271 fails, and an IEmissary is set for the sponsor, an
     * IEmissary.verifyClaim check is performed.
     * @param claimHash           The EIP-712 hash of the claim to verify.
     * @param expectedSigner      The address that should have signed the message.
     * @param signature           The signature to verify.
     * @param domainSeparator     The domain separator to combine with the message hash.
     * @param typehash            The EIP-712 typehash used for the claim message.
     */
    function validateSponsorAndConsumeRegistration(
        bytes32 claimHash,
        address expectedSigner,
        bytes calldata signature,
        bytes32 domainSeparator,
        uint256[2][] memory idsAndAmounts,
        bytes32 typehash
    ) internal {
        if (expectedSigner.consumeRegistrationIfRegistered(claimHash, typehash)) {
            return;
        }

        // Apply domain separator to message hash to derive the digest.
        bytes32 digest = claimHash.withDomain(domainSeparator);

        // First, check signature against digest with ECDSA (or ensure sponsor is caller).
        if (expectedSigner.isValidECDSASignatureCalldata(digest, signature)) {
            return;
        }

        // Then, check EIP1271 using the digest, supplying half of available gas.
        if (expectedSigner.isValidERC1271SignatureNowCalldataHalfGas(digest, signature)) {
            return;
        }

        // Finally, fallback to emissary using the claim hash.
        digest.verifyWithEmissary(claimHash, expectedSigner, idsAndAmounts.extractSameLockTag(), signature);
    }

    /**
     * @notice Internal view function to check if a nonce has been consumed in an
     * allocator's scope.
     * @param allocator The allocator whose scope to check.
     * @param nonce     The nonce to check.
     * @return          Whether the nonce has been consumed.
     */
    function hasConsumedAllocatorNonce(address allocator, uint256 nonce) internal view returns (bool) {
        return nonce.isConsumedByAllocator(allocator);
    }

    /**
     * @notice Internal pure function that validates a token address is not the zero
     * address (which represents native tokens). Reverts if the address is zero.
     * @param token The token address to validate.
     * @return      The validated token address.
     */
    function excludingNative(address token) internal pure returns (address) {
        assembly ("memory-safe") {
            if iszero(shl(96, token)) {
                // revert InvalidToken(0);
                mstore(0x40, 0x961c9a4f)
                revert(0x5c, 0x24)
            }
        }

        return token;
    }

    /**
     * @notice Internal pure function for validating that a resource lock's scope is compatible
     * with the provided sponsor domain separator. Reverts if an exogenous claim (indicated by
     * a non-zero sponsor domain separator) attempts to claim against a chain-specific resource
     * lock (indicated by the most significant bit of the id).
     * @param sponsorDomainSeparator The domain separator for the sponsor's signature, or zero for non-exogenous claims.
     * @param id                     The ERC6909 token identifier of the resource lock.
     */
    function ensureValidScope(bytes32 sponsorDomainSeparator, uint256 id) internal pure {
        assembly ("memory-safe") {
            if iszero(or(iszero(sponsorDomainSeparator), iszero(shr(255, id)))) {
                // revert InvalidScope(id)
                mstore(0, 0xa06356f5)
                mstore(0x20, id)
                revert(0x1c, 0x24)
            }
        }
    }

    /**
     * @notice Internal pure function for determining if a resource lock has chain-specific
     * scope in the context of an exogenous claim. Returns true if the claim is exogenous
     * (indicated by a non-zero sponsor domain separator) and the resource lock is
     * chain-specific.
     * @param id                     The ERC6909 token identifier of the resource lock.
     * @param sponsorDomainSeparator The domain separator for the sponsor's signature, or zero for non-exogenous claims.
     * @return                       Whether the resource lock's scope is incompatible with the claim context.
     */
    function scopeNotMultichain(uint256 id, bytes32 sponsorDomainSeparator) internal pure returns (bool) {
        return (sponsorDomainSeparator != bytes32(0)).and(id.toScope() == Scope.ChainSpecific);
    }

    /// @dev Returns whether `signature` is valid for `signer` and `hash`.
    /// using `ecrecover`.
    function isValidECDSASignatureCalldata(address signer, bytes32 hash, bytes calldata signature)
        internal
        view
        returns (bool isValid)
    {
        // Determine whether the signer is the caller.
        bool signerIsCaller = signer == msg.sender;

        // Exit early if signer is either the caller or the null address.
        if ((signer == address(0)).or(signerIsCaller)) {
            // Valid if signer is caller, otherwise invalid (null address).
            return signerIsCaller;
        }

        assembly ("memory-safe") {
            // Cache free memory pointer.
            let m := mload(0x40)

            // Use a faux loop to support breaking early.
            for { } 1 { } {
                // examine the length of the supplied signature.
                switch signature.length
                case 64 {
                    // Parse length 64 as EIP2098 compact signatures.
                    let vs := calldataload(add(signature.offset, 0x20))
                    mstore(0x20, add(shr(255, vs), 27)) // `v`.
                    mstore(0x40, calldataload(signature.offset)) // `r`.
                    mstore(0x60, shr(1, shl(1, vs))) // `s`.
                }
                case 65 {
                    // Parse length 65 as standard rsv signatures.
                    mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
                    calldatacopy(0x40, signature.offset, 0x40) // `r`, `s`.
                }
                default { break }

                // Prepare hash in scratch space.
                mstore(0x00, hash)

                // Call the ecrecover precompile and examine returndata for validity.
                let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
                isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))

                // Restore the zero slot and free memory pointer.
                mstore(0x60, 0)
                mstore(0x40, m)
                break
            }
        }
    }

    /// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract.
    /// Sourced from Solady with a modification to only supply half of available gas.
    function isValidERC1271SignatureNowCalldataHalfGas(address signer, bytes32 hash, bytes calldata signature)
        internal
        view
        returns (bool isValid)
    {
        assembly ("memory-safe") {
            let m := mload(0x40)
            let f := shl(224, 0x1626ba7e)
            mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
            mstore(add(m, 0x04), hash)
            let d := add(m, 0x24)
            mstore(d, 0x40) // The offset of the `signature` in the calldata.
            mstore(add(m, 0x44), signature.length)
            // Copy the `signature` over.
            calldatacopy(add(m, 0x64), signature.offset, signature.length)
            isValid := staticcall(div(gas(), 2), signer, m, add(signature.length, 0x64), d, 0x20)
            isValid := and(eq(mload(d), f), isValid)
        }
    }
}

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

import { Scope } from "../types/Scope.sol";
import { ResetPeriod } from "../types/ResetPeriod.sol";

/**
 * @title EfficiencyLib
 * @notice Library contract implementing logic for efficient value comparisons,
 * conversions, typecasting, and sanitization. Also provides functions to prevent
 * the function specializer from being triggered when using static arguments.
 */
library EfficiencyLib {
    /**
     * @notice Internal view function to convert the provided account address to the caller if that
     *         address is the null address (0x0).
     * @dev    Uses bitwise operations to avoid branching, making this function more gas efficient
     *         than using a traditional if-else statement. The implementation follows the pattern
     *         `result = xor(a, mul(xor(a, b), condition))` which resolves to either a or b based
     *         on the condition; as the condition in this case is contingent on the first argument
     *         having a value of zero, the nested xor can safely be omitted.
     * @param  account               The address to check and potentially replace.
     * @return accountOrCallerIfNull The original address if non-zero, otherwise msg.sender.
     */
    function usingCallerIfNull(address account) internal view returns (address accountOrCallerIfNull) {
        assembly ("memory-safe") {
            accountOrCallerIfNull := xor(account, mul(caller(), iszero(account)))
        }
    }

    /**
     * @notice Internal pure function that performs a bitwise AND on two booleans.
     * Avoids Solidity's conditional evaluation of logical AND. Only safe when
     * inputs are known to be exactly 0 or 1 with no dirty bits.
     * @param a  The first boolean value.
     * @param b  The second boolean value.
     * @return c The result of the bitwise AND.
     */
    function and(bool a, bool b) internal pure returns (bool c) {
        assembly ("memory-safe") {
            c := and(a, b)
        }
    }

    /**
     * @notice Internal pure function that performs a bitwise OR on two booleans.
     * Avoids Solidity's conditional evaluation of logical OR. Only safe when
     * inputs are known to be exactly 0 or 1 with no dirty bits.
     * @param a  The first boolean value.
     * @param b  The second boolean value.
     * @return c The result of the bitwise OR.
     */
    function or(bool a, bool b) internal pure returns (bool c) {
        assembly ("memory-safe") {
            c := or(a, b)
        }
    }

    /**
     * @notice Internal pure function that sanitizes an address by clearing the
     * upper 96 bits. Used for ensuring consistent address handling.
     * @param accountValue The value to sanitize.
     * @return account     The sanitized address.
     */
    function asSanitizedAddress(uint256 accountValue) internal pure returns (address account) {
        assembly ("memory-safe") {
            account := shr(96, shl(96, accountValue))
        }
    }

    /**
     * @notice Internal pure function that checks if an address has its lower 160
     * bits set to zero.
     * @param account The address to check.
     * @return isNull Whether the address is null.
     */
    function isNullAddress(address account) internal pure returns (bool isNull) {
        assembly ("memory-safe") {
            isNull := iszero(shl(96, account))
        }
    }

    /**
     * @notice Internal pure function that converts a boolean to a uint256.
     * @param a  The boolean to convert.
     * @return b The resulting uint256.
     */
    function asUint256(bool a) internal pure returns (uint256 b) {
        assembly ("memory-safe") {
            b := a
        }
    }

    /**
     * @notice Internal pure function that converts a uint96 to a uint256.
     * @param a  The uint96 to convert.
     * @return b The resulting uint256.
     */
    function asUint256(uint96 a) internal pure returns (uint256 b) {
        assembly ("memory-safe") {
            b := a
        }
    }

    /**
     * @notice Internal pure function that converts a bytes12 to a uint256.
     * @param a  The bytes12 to convert.
     * @return b The resulting uint256.
     */
    function asUint256(bytes12 a) internal pure returns (uint256 b) {
        assembly ("memory-safe") {
            b := a
        }
    }

    /**
     * @notice Internal pure function that converts a Scope enum to a uint256.
     * @param a  The Scope enum to convert.
     * @return b The resulting uint256.
     */
    function asUint256(Scope a) internal pure returns (uint256 b) {
        assembly ("memory-safe") {
            b := a
        }
    }

    /**
     * @notice Internal pure function that converts an address to a uint256.
     * @param a  The address to convert.
     * @return b The resulting uint256.
     */
    function asUint256(address a) internal pure returns (uint256 b) {
        assembly ("memory-safe") {
            b := a
        }
    }

    /**
     * @notice Internal pure function that converts a ResetPeriod enum to a uint256.
     * @param a  The ResetPeriod enum to convert.
     * @return b The resulting uint256.
     */
    function asUint256(ResetPeriod a) internal pure returns (uint256 b) {
        assembly ("memory-safe") {
            b := a
        }
    }

    /**
     * @notice Internal pure function that prevents the function specializer from
     * optimizing uint256 arguments. XORs the value with calldatasize(), which
     * will always be non-zero in a real call.
     * @param a  The uint256 value to make stubborn.
     * @return b The original value, preventing specialization.
     */
    function asStubborn(uint256 a) internal pure returns (uint256 b) {
        assembly ("memory-safe") {
            b := or(iszero(calldatasize()), a)
        }
    }

    /**
     * @notice Internal pure function that prevents the function specializer from
     * inlining functions that take fixed boolean arguments. Since calldatasize()
     * will always be non-zero when making a standard function call, an OR
     * against iszero(calldatasize()) will always result in the original value.
     * @param a  The boolean value to make stubborn.
     * @return b The original value, preventing specialization.
     */
    function asStubborn(bool a) internal pure returns (bool b) {
        assembly ("memory-safe") {
            b := or(iszero(calldatasize()), a)
        }
    }
}

File 5 of 41 : FixedPointMathLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The operation failed, as the output exceeds the maximum value of uint256.
    error ExpOverflow();

    /// @dev The operation failed, as the output exceeds the maximum value of uint256.
    error FactorialOverflow();

    /// @dev The operation failed, due to an overflow.
    error RPowOverflow();

    /// @dev The mantissa is too big to fit.
    error MantissaOverflow();

    /// @dev The operation failed, due to an multiplication overflow.
    error MulWadFailed();

    /// @dev The operation failed, due to an multiplication overflow.
    error SMulWadFailed();

    /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
    error DivWadFailed();

    /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
    error SDivWadFailed();

    /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
    error MulDivFailed();

    /// @dev The division failed, as the denominator is zero.
    error DivFailed();

    /// @dev The full precision multiply-divide operation failed, either due
    /// to the result being larger than 256 bits, or a division by a zero.
    error FullMulDivFailed();

    /// @dev The output is undefined, as the input is less-than-or-equal to zero.
    error LnWadUndefined();

    /// @dev The input outside the acceptable domain.
    error OutOfDomain();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The scalar of ETH and most ERC20s.
    uint256 internal constant WAD = 1e18;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*              SIMPLIFIED FIXED POINT OPERATIONS             */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Equivalent to `(x * y) / WAD` rounded down.
    function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
            if gt(x, div(not(0), y)) {
                if y {
                    mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            z := div(mul(x, y), WAD)
        }
    }

    /// @dev Equivalent to `(x * y) / WAD` rounded down.
    function sMulWad(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(x, y)
            // Equivalent to `require((x == 0 || z / x == y) && !(x == -1 && y == type(int256).min))`.
            if iszero(gt(or(iszero(x), eq(sdiv(z, x), y)), lt(not(x), eq(y, shl(255, 1))))) {
                mstore(0x00, 0xedcd4dd4) // `SMulWadFailed()`.
                revert(0x1c, 0x04)
            }
            z := sdiv(z, WAD)
        }
    }

    /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
    function rawMulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := div(mul(x, y), WAD)
        }
    }

    /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
    function rawSMulWad(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := sdiv(mul(x, y), WAD)
        }
    }

    /// @dev Equivalent to `(x * y) / WAD` rounded up.
    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(x, y)
            // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
            if iszero(eq(div(z, y), x)) {
                if y {
                    mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            z := add(iszero(iszero(mod(z, WAD))), div(z, WAD))
        }
    }

    /// @dev Equivalent to `(x * y) / WAD` rounded up, but without overflow checks.
    function rawMulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
        }
    }

    /// @dev Equivalent to `(x * WAD) / y` rounded down.
    function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to `require(y != 0 && x <= type(uint256).max / WAD)`.
            if iszero(mul(y, lt(x, add(1, div(not(0), WAD))))) {
                mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
                revert(0x1c, 0x04)
            }
            z := div(mul(x, WAD), y)
        }
    }

    /// @dev Equivalent to `(x * WAD) / y` rounded down.
    function sDivWad(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(x, WAD)
            // Equivalent to `require(y != 0 && ((x * WAD) / WAD == x))`.
            if iszero(mul(y, eq(sdiv(z, WAD), x))) {
                mstore(0x00, 0x5c43740d) // `SDivWadFailed()`.
                revert(0x1c, 0x04)
            }
            z := sdiv(z, y)
        }
    }

    /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
    function rawDivWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := div(mul(x, WAD), y)
        }
    }

    /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
    function rawSDivWad(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := sdiv(mul(x, WAD), y)
        }
    }

    /// @dev Equivalent to `(x * WAD) / y` rounded up.
    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to `require(y != 0 && x <= type(uint256).max / WAD)`.
            if iszero(mul(y, lt(x, add(1, div(not(0), WAD))))) {
                mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
                revert(0x1c, 0x04)
            }
            z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
        }
    }

    /// @dev Equivalent to `(x * WAD) / y` rounded up, but without overflow and divide by zero checks.
    function rawDivWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
        }
    }

    /// @dev Equivalent to `x` to the power of `y`.
    /// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`.
    /// Note: This function is an approximation.
    function powWad(int256 x, int256 y) internal pure returns (int256) {
        // Using `ln(x)` means `x` must be greater than 0.
        return expWad((lnWad(x) * y) / int256(WAD));
    }

    /// @dev Returns `exp(x)`, denominated in `WAD`.
    /// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln
    /// Note: This function is an approximation. Monotonically increasing.
    function expWad(int256 x) internal pure returns (int256 r) {
        unchecked {
            // When the result is less than 0.5 we return zero.
            // This happens when `x <= (log(1e-18) * 1e18) ~ -4.15e19`.
            if (x <= -41446531673892822313) return r;

            /// @solidity memory-safe-assembly
            assembly {
                // When the result is greater than `(2**255 - 1) / 1e18` we can not represent it as
                // an int. This happens when `x >= floor(log((2**255 - 1) / 1e18) * 1e18) ≈ 135`.
                if iszero(slt(x, 135305999368893231589)) {
                    mstore(0x00, 0xa37bfec9) // `ExpOverflow()`.
                    revert(0x1c, 0x04)
                }
            }

            // `x` is now in the range `(-42, 136) * 1e18`. Convert to `(-42, 136) * 2**96`
            // for more intermediate precision and a binary basis. This base conversion
            // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
            x = (x << 78) / 5 ** 18;

            // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
            // of two such that exp(x) = exp(x') * 2**k, where k is an integer.
            // Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
            int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96;
            x = x - k * 54916777467707473351141471128;

            // `k` is in the range `[-61, 195]`.

            // Evaluate using a (6, 7)-term rational approximation.
            // `p` is made monic, we'll multiply by a scale factor later.
            int256 y = x + 1346386616545796478920950773328;
            y = ((y * x) >> 96) + 57155421227552351082224309758442;
            int256 p = y + x - 94201549194550492254356042504812;
            p = ((p * y) >> 96) + 28719021644029726153956944680412240;
            p = p * x + (4385272521454847904659076985693276 << 96);

            // We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
            int256 q = x - 2855989394907223263936484059900;
            q = ((q * x) >> 96) + 50020603652535783019961831881945;
            q = ((q * x) >> 96) - 533845033583426703283633433725380;
            q = ((q * x) >> 96) + 3604857256930695427073651918091429;
            q = ((q * x) >> 96) - 14423608567350463180887372962807573;
            q = ((q * x) >> 96) + 26449188498355588339934803723976023;

            /// @solidity memory-safe-assembly
            assembly {
                // Div in assembly because solidity adds a zero check despite the unchecked.
                // The q polynomial won't have zeros in the domain as all its roots are complex.
                // No scaling is necessary because p is already `2**96` too large.
                r := sdiv(p, q)
            }

            // r should be in the range `(0.09, 0.25) * 2**96`.

            // We now need to multiply r by:
            // - The scale factor `s ≈ 6.031367120`.
            // - The `2**k` factor from the range reduction.
            // - The `1e18 / 2**96` factor for base conversion.
            // We do this all at once, with an intermediate result in `2**213`
            // basis, so the final right shift is always by a positive amount.
            r = int256(
                (uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k)
            );
        }
    }

    /// @dev Returns `ln(x)`, denominated in `WAD`.
    /// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln
    /// Note: This function is an approximation. Monotonically increasing.
    function lnWad(int256 x) internal pure returns (int256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            // We want to convert `x` from `10**18` fixed point to `2**96` fixed point.
            // We do this by multiplying by `2**96 / 10**18`. But since
            // `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here
            // and add `ln(2**96 / 10**18)` at the end.

            // Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`.
            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            // We place the check here for more optimal stack operations.
            if iszero(sgt(x, 0)) {
                mstore(0x00, 0x1615e638) // `LnWadUndefined()`.
                revert(0x1c, 0x04)
            }
            // forgefmt: disable-next-item
            r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
                0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff))

            // Reduce range of x to (1, 2) * 2**96
            // ln(2^k * x) = k * ln(2) + ln(x)
            x := shr(159, shl(r, x))

            // Evaluate using a (8, 8)-term rational approximation.
            // `p` is made monic, we will multiply by a scale factor later.
            // forgefmt: disable-next-item
            let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir.
                sar(96, mul(add(43456485725739037958740375743393,
                sar(96, mul(add(24828157081833163892658089445524,
                sar(96, mul(add(3273285459638523848632254066296,
                    x), x))), x))), x)), 11111509109440967052023855526967)
            p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857)
            p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526)
            p := sub(mul(p, x), shl(96, 795164235651350426258249787498))
            // We leave `p` in `2**192` basis so we don't need to scale it back up for the division.

            // `q` is monic by convention.
            let q := add(5573035233440673466300451813936, x)
            q := add(71694874799317883764090561454958, sar(96, mul(x, q)))
            q := add(283447036172924575727196451306956, sar(96, mul(x, q)))
            q := add(401686690394027663651624208769553, sar(96, mul(x, q)))
            q := add(204048457590392012362485061816622, sar(96, mul(x, q)))
            q := add(31853899698501571402653359427138, sar(96, mul(x, q)))
            q := add(909429971244387300277376558375, sar(96, mul(x, q)))

            // `p / q` is in the range `(0, 0.125) * 2**96`.

            // Finalization, we need to:
            // - Multiply by the scale factor `s = 5.549…`.
            // - Add `ln(2**96 / 10**18)`.
            // - Add `k * ln(2)`.
            // - Multiply by `10**18 / 2**96 = 5**18 >> 78`.

            // The q polynomial is known not to have zeros in the domain.
            // No scaling required because p is already `2**96` too large.
            p := sdiv(p, q)
            // Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`.
            p := mul(1677202110996718588342820967067443963516166, p)
            // Add `ln(2) * k * 5**18 * 2**192`.
            // forgefmt: disable-next-item
            p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p)
            // Add `ln(2**96 / 10**18) * 5**18 * 2**192`.
            p := add(600920179829731861736702779321621459595472258049074101567377883020018308, p)
            // Base conversion: mul `2**18 / 2**192`.
            r := sar(174, p)
        }
    }

    /// @dev Returns `W_0(x)`, denominated in `WAD`.
    /// See: https://en.wikipedia.org/wiki/Lambert_W_function
    /// a.k.a. Product log function. This is an approximation of the principal branch.
    /// Note: This function is an approximation. Monotonically increasing.
    function lambertW0Wad(int256 x) internal pure returns (int256 w) {
        // forgefmt: disable-next-item
        unchecked {
            if ((w = x) <= -367879441171442322) revert OutOfDomain(); // `x` less than `-1/e`.
            (int256 wad, int256 p) = (int256(WAD), x);
            uint256 c; // Whether we need to avoid catastrophic cancellation.
            uint256 i = 4; // Number of iterations.
            if (w <= 0x1ffffffffffff) {
                if (-0x4000000000000 <= w) {
                    i = 1; // Inputs near zero only take one step to converge.
                } else if (w <= -0x3ffffffffffffff) {
                    i = 32; // Inputs near `-1/e` take very long to converge.
                }
            } else if (uint256(w >> 63) == uint256(0)) {
                /// @solidity memory-safe-assembly
                assembly {
                    // Inline log2 for more performance, since the range is small.
                    let v := shr(49, w)
                    let l := shl(3, lt(0xff, v))
                    l := add(or(l, byte(and(0x1f, shr(shr(l, v), 0x8421084210842108cc6318c6db6d54be)),
                        0x0706060506020504060203020504030106050205030304010505030400000000)), 49)
                    w := sdiv(shl(l, 7), byte(sub(l, 31), 0x0303030303030303040506080c13))
                    c := gt(l, 60)
                    i := add(2, add(gt(l, 53), c))
                }
            } else {
                int256 ll = lnWad(w = lnWad(w));
                /// @solidity memory-safe-assembly
                assembly {
                    // `w = ln(x) - ln(ln(x)) + b * ln(ln(x)) / ln(x)`.
                    w := add(sdiv(mul(ll, 1023715080943847266), w), sub(w, ll))
                    i := add(3, iszero(shr(68, x)))
                    c := iszero(shr(143, x))
                }
                if (c == uint256(0)) {
                    do { // If `x` is big, use Newton's so that intermediate values won't overflow.
                        int256 e = expWad(w);
                        /// @solidity memory-safe-assembly
                        assembly {
                            let t := mul(w, div(e, wad))
                            w := sub(w, sdiv(sub(t, x), div(add(e, t), wad)))
                        }
                        if (p <= w) break;
                        p = w;
                    } while (--i != uint256(0));
                    /// @solidity memory-safe-assembly
                    assembly {
                        w := sub(w, sgt(w, 2))
                    }
                    return w;
                }
            }
            do { // Otherwise, use Halley's for faster convergence.
                int256 e = expWad(w);
                /// @solidity memory-safe-assembly
                assembly {
                    let t := add(w, wad)
                    let s := sub(mul(w, e), mul(x, wad))
                    w := sub(w, sdiv(mul(s, wad), sub(mul(e, t), sdiv(mul(add(t, wad), s), add(t, t)))))
                }
                if (p <= w) break;
                p = w;
            } while (--i != c);
            /// @solidity memory-safe-assembly
            assembly {
                w := sub(w, sgt(w, 2))
            }
            // For certain ranges of `x`, we'll use the quadratic-rate recursive formula of
            // R. Iacono and J.P. Boyd for the last iteration, to avoid catastrophic cancellation.
            if (c == uint256(0)) return w;
            int256 t = w | 1;
            /// @solidity memory-safe-assembly
            assembly {
                x := sdiv(mul(x, wad), t)
            }
            x = (t * (wad + lnWad(x)));
            /// @solidity memory-safe-assembly
            assembly {
                w := sdiv(x, add(wad, t))
            }
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  GENERAL NUMBER UTILITIES                  */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns `a * b == x * y`, with full precision.
    function fullMulEq(uint256 a, uint256 b, uint256 x, uint256 y)
        internal
        pure
        returns (bool result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            result := and(eq(mul(a, b), mul(x, y)), eq(mulmod(x, y, not(0)), mulmod(a, b, not(0))))
        }
    }

    /// @dev Calculates `floor(x * y / d)` with full precision.
    /// Throws if result overflows a uint256 or when `d` is zero.
    /// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv
    function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // 512-bit multiply `[p1 p0] = x * y`.
            // Compute the product mod `2**256` and mod `2**256 - 1`
            // then use the Chinese Remainder Theorem to reconstruct
            // the 512 bit result. The result is stored in two 256
            // variables such that `product = p1 * 2**256 + p0`.

            // Temporarily use `z` as `p0` to save gas.
            z := mul(x, y) // Lower 256 bits of `x * y`.
            for {} 1 {} {
                // If overflows.
                if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) {
                    let mm := mulmod(x, y, not(0))
                    let p1 := sub(mm, add(z, lt(mm, z))) // Upper 256 bits of `x * y`.

                    /*------------------- 512 by 256 division --------------------*/

                    // Make division exact by subtracting the remainder from `[p1 p0]`.
                    let r := mulmod(x, y, d) // Compute remainder using mulmod.
                    let t := and(d, sub(0, d)) // The least significant bit of `d`. `t >= 1`.
                    // Make sure `z` is less than `2**256`. Also prevents `d == 0`.
                    // Placing the check here seems to give more optimal stack operations.
                    if iszero(gt(d, p1)) {
                        mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
                        revert(0x1c, 0x04)
                    }
                    d := div(d, t) // Divide `d` by `t`, which is a power of two.
                    // Invert `d mod 2**256`
                    // Now that `d` is an odd number, it has an inverse
                    // modulo `2**256` such that `d * inv = 1 mod 2**256`.
                    // Compute the inverse by starting with a seed that is correct
                    // correct for four bits. That is, `d * inv = 1 mod 2**4`.
                    let inv := xor(2, mul(3, d))
                    // Now use 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.
                    inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8
                    inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16
                    inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32
                    inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64
                    inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128
                    z :=
                        mul(
                            // Divide [p1 p0] by the factors of two.
                            // Shift in bits from `p1` into `p0`. For this we need
                            // to flip `t` such that it is `2**256 / t`.
                            or(mul(sub(p1, gt(r, z)), add(div(sub(0, t), t), 1)), div(sub(z, r), t)),
                            mul(sub(2, mul(d, inv)), inv) // inverse mod 2**256
                        )
                    break
                }
                z := div(z, d)
                break
            }
        }
    }

    /// @dev Calculates `floor(x * y / d)` with full precision.
    /// Behavior is undefined if `d` is zero or the final result cannot fit in 256 bits.
    /// Performs the full 512 bit calculation regardless.
    function fullMulDivUnchecked(uint256 x, uint256 y, uint256 d)
        internal
        pure
        returns (uint256 z)
    {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(x, y)
            let mm := mulmod(x, y, not(0))
            let p1 := sub(mm, add(z, lt(mm, z)))
            let t := and(d, sub(0, d))
            let r := mulmod(x, y, d)
            d := div(d, t)
            let inv := xor(2, mul(3, d))
            inv := mul(inv, sub(2, mul(d, inv)))
            inv := mul(inv, sub(2, mul(d, inv)))
            inv := mul(inv, sub(2, mul(d, inv)))
            inv := mul(inv, sub(2, mul(d, inv)))
            inv := mul(inv, sub(2, mul(d, inv)))
            z :=
                mul(
                    or(mul(sub(p1, gt(r, z)), add(div(sub(0, t), t), 1)), div(sub(z, r), t)),
                    mul(sub(2, mul(d, inv)), inv)
                )
        }
    }

    /// @dev Calculates `floor(x * y / d)` with full precision, rounded up.
    /// Throws if result overflows a uint256 or when `d` is zero.
    /// Credit to Uniswap-v3-core under MIT license:
    /// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol
    function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
        z = fullMulDiv(x, y, d);
        /// @solidity memory-safe-assembly
        assembly {
            if mulmod(x, y, d) {
                z := add(z, 1)
                if iszero(z) {
                    mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
                    revert(0x1c, 0x04)
                }
            }
        }
    }

    /// @dev Calculates `floor(x * y / 2 ** n)` with full precision.
    /// Throws if result overflows a uint256.
    /// Credit to Philogy under MIT license:
    /// https://github.com/SorellaLabs/angstrom/blob/main/contracts/src/libraries/X128MathLib.sol
    function fullMulDivN(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Temporarily use `z` as `p0` to save gas.
            z := mul(x, y) // Lower 256 bits of `x * y`. We'll call this `z`.
            for {} 1 {} {
                if iszero(or(iszero(x), eq(div(z, x), y))) {
                    let k := and(n, 0xff) // `n`, cleaned.
                    let mm := mulmod(x, y, not(0))
                    let p1 := sub(mm, add(z, lt(mm, z))) // Upper 256 bits of `x * y`.
                    //         |      p1     |      z     |
                    // Before: | p1_0 ¦ p1_1 | z_0  ¦ z_1 |
                    // Final:  |   0  ¦ p1_0 | p1_1 ¦ z_0 |
                    // Check that final `z` doesn't overflow by checking that p1_0 = 0.
                    if iszero(shr(k, p1)) {
                        z := add(shl(sub(256, k), p1), shr(k, z))
                        break
                    }
                    mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
                    revert(0x1c, 0x04)
                }
                z := shr(and(n, 0xff), z)
                break
            }
        }
    }

    /// @dev Returns `floor(x * y / d)`.
    /// Reverts if `x * y` overflows, or `d` is zero.
    function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(x, y)
            // Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`.
            if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) {
                mstore(0x00, 0xad251c27) // `MulDivFailed()`.
                revert(0x1c, 0x04)
            }
            z := div(z, d)
        }
    }

    /// @dev Returns `ceil(x * y / d)`.
    /// Reverts if `x * y` overflows, or `d` is zero.
    function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(x, y)
            // Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`.
            if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) {
                mstore(0x00, 0xad251c27) // `MulDivFailed()`.
                revert(0x1c, 0x04)
            }
            z := add(iszero(iszero(mod(z, d))), div(z, d))
        }
    }

    /// @dev Returns `x`, the modular multiplicative inverse of `a`, such that `(a * x) % n == 1`.
    function invMod(uint256 a, uint256 n) internal pure returns (uint256 x) {
        /// @solidity memory-safe-assembly
        assembly {
            let g := n
            let r := mod(a, n)
            for { let y := 1 } 1 {} {
                let q := div(g, r)
                let t := g
                g := r
                r := sub(t, mul(r, q))
                let u := x
                x := y
                y := sub(u, mul(y, q))
                if iszero(r) { break }
            }
            x := mul(eq(g, 1), add(x, mul(slt(x, 0), n)))
        }
    }

    /// @dev Returns `ceil(x / d)`.
    /// Reverts if `d` is zero.
    function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(d) {
                mstore(0x00, 0x65244e4e) // `DivFailed()`.
                revert(0x1c, 0x04)
            }
            z := add(iszero(iszero(mod(x, d))), div(x, d))
        }
    }

    /// @dev Returns `max(0, x - y)`. Alias for `saturatingSub`.
    function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(gt(x, y), sub(x, y))
        }
    }

    /// @dev Returns `max(0, x - y)`.
    function saturatingSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(gt(x, y), sub(x, y))
        }
    }

    /// @dev Returns `min(2 ** 256 - 1, x + y)`.
    function saturatingAdd(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := or(sub(0, lt(add(x, y), x)), add(x, y))
        }
    }

    /// @dev Returns `min(2 ** 256 - 1, x * y)`.
    function saturatingMul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := or(sub(or(iszero(x), eq(div(mul(x, y), x), y)), 1), mul(x, y))
        }
    }

    /// @dev Returns `condition ? x : y`, without branching.
    function ternary(bool condition, uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, y), iszero(condition)))
        }
    }

    /// @dev Returns `condition ? x : y`, without branching.
    function ternary(bool condition, bytes32 x, bytes32 y) internal pure returns (bytes32 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, y), iszero(condition)))
        }
    }

    /// @dev Returns `condition ? x : y`, without branching.
    function ternary(bool condition, address x, address y) internal pure returns (address z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, y), iszero(condition)))
        }
    }

    /// @dev Returns `x != 0 ? x : y`, without branching.
    function coalesce(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := or(x, mul(y, iszero(x)))
        }
    }

    /// @dev Returns `x != bytes32(0) ? x : y`, without branching.
    function coalesce(bytes32 x, bytes32 y) internal pure returns (bytes32 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := or(x, mul(y, iszero(x)))
        }
    }

    /// @dev Returns `x != address(0) ? x : y`, without branching.
    function coalesce(address x, address y) internal pure returns (address z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := or(x, mul(y, iszero(shl(96, x))))
        }
    }

    /// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`.
    /// Reverts if the computation overflows.
    function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`.
            if x {
                z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x`
                let half := shr(1, b) // Divide `b` by 2.
                // Divide `y` by 2 every iteration.
                for { y := shr(1, y) } y { y := shr(1, y) } {
                    let xx := mul(x, x) // Store x squared.
                    let xxRound := add(xx, half) // Round to the nearest number.
                    // Revert if `xx + half` overflowed, or if `x ** 2` overflows.
                    if or(lt(xxRound, xx), shr(128, x)) {
                        mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
                        revert(0x1c, 0x04)
                    }
                    x := div(xxRound, b) // Set `x` to scaled `xxRound`.
                    // If `y` is odd:
                    if and(y, 1) {
                        let zx := mul(z, x) // Compute `z * x`.
                        let zxRound := add(zx, half) // Round to the nearest number.
                        // If `z * x` overflowed or `zx + half` overflowed:
                        if or(xor(div(zx, x), z), lt(zxRound, zx)) {
                            // Revert if `x` is non-zero.
                            if x {
                                mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
                                revert(0x1c, 0x04)
                            }
                        }
                        z := div(zxRound, b) // Return properly scaled `zxRound`.
                    }
                }
            }
        }
    }

    /// @dev Returns the square root of `x`, rounded down.
    function sqrt(uint256 x) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`.
            z := 181 // The "correct" value is 1, but this saves a multiplication later.

            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.

            // Let `y = x / 2**r`. We check `y >= 2**(k + 8)`
            // but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`.
            let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffffff, shr(r, x))))
            z := shl(shr(1, r), z)

            // Goal was to get `z*z*y` within a small factor of `x`. More iterations could
            // get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`.
            // We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small.
            // That's not possible if `x < 256` but we can just verify those cases exhaustively.

            // Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`.
            // Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`.
            // Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps.

            // For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)`
            // is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`,
            // with largest error when `s = 1` and when `s = 256` or `1/256`.

            // Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`.
            // Then we can estimate `sqrt(y)` using
            // `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`.

            // There is no overflow risk here since `y < 2**136` after the first branch above.
            z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181.

            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))

            // If `x+1` is a perfect square, the Babylonian method cycles between
            // `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor.
            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
            z := sub(z, lt(div(x, z), z))
        }
    }

    /// @dev Returns the cube root of `x`, rounded down.
    /// Credit to bout3fiddy and pcaversaccio under AGPLv3 license:
    /// https://github.com/pcaversaccio/snekmate/blob/main/src/snekmate/utils/math.vy
    /// Formally verified by xuwinnie:
    /// https://github.com/vectorized/solady/blob/main/audits/xuwinnie-solady-cbrt-proof.pdf
    function cbrt(uint256 x) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            // Makeshift lookup table to nudge the approximate log2 result.
            z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3)))
            // Newton-Raphson's.
            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            // Round down.
            z := sub(z, lt(div(x, mul(z, z)), z))
        }
    }

    /// @dev Returns the square root of `x`, denominated in `WAD`, rounded down.
    function sqrtWad(uint256 x) internal pure returns (uint256 z) {
        unchecked {
            if (x <= type(uint256).max / 10 ** 18) return sqrt(x * 10 ** 18);
            z = (1 + sqrt(x)) * 10 ** 9;
            z = (fullMulDivUnchecked(x, 10 ** 18, z) + z) >> 1;
        }
        /// @solidity memory-safe-assembly
        assembly {
            z := sub(z, gt(999999999999999999, sub(mulmod(z, z, x), 1))) // Round down.
        }
    }

    /// @dev Returns the cube root of `x`, denominated in `WAD`, rounded down.
    /// Formally verified by xuwinnie:
    /// https://github.com/vectorized/solady/blob/main/audits/xuwinnie-solady-cbrt-proof.pdf
    function cbrtWad(uint256 x) internal pure returns (uint256 z) {
        unchecked {
            if (x <= type(uint256).max / 10 ** 36) return cbrt(x * 10 ** 36);
            z = (1 + cbrt(x)) * 10 ** 12;
            z = (fullMulDivUnchecked(x, 10 ** 36, z * z) + z + z) / 3;
        }
        /// @solidity memory-safe-assembly
        assembly {
            let p := x
            for {} 1 {} {
                if iszero(shr(229, p)) {
                    if iszero(shr(199, p)) {
                        p := mul(p, 100000000000000000) // 10 ** 17.
                        break
                    }
                    p := mul(p, 100000000) // 10 ** 8.
                    break
                }
                if iszero(shr(249, p)) { p := mul(p, 100) }
                break
            }
            let t := mulmod(mul(z, z), z, p)
            z := sub(z, gt(lt(t, shr(1, p)), iszero(t))) // Round down.
        }
    }

    /// @dev Returns `sqrt(x * y)`. Also called the geometric mean.
    function mulSqrt(uint256 x, uint256 y) internal pure returns (uint256 z) {
        if (x == y) return x;
        uint256 p = rawMul(x, y);
        if (y == rawDiv(p, x)) return sqrt(p);
        for (z = saturatingMul(rawAdd(sqrt(x), 1), rawAdd(sqrt(y), 1));; z = avg(z, p)) {
            if ((p = fullMulDivUnchecked(x, y, z)) >= z) break;
        }
    }

    /// @dev Returns the factorial of `x`.
    function factorial(uint256 x) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := 1
            if iszero(lt(x, 58)) {
                mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`.
                revert(0x1c, 0x04)
            }
            for {} x { x := sub(x, 1) } { z := mul(z, x) }
        }
    }

    /// @dev Returns the log2 of `x`.
    /// Equivalent to computing the index of the most significant bit (MSB) of `x`.
    /// Returns 0 if `x` is zero.
    function log2(uint256 x) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            // forgefmt: disable-next-item
            r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
                0x0706060506020504060203020504030106050205030304010505030400000000))
        }
    }

    /// @dev Returns the log2 of `x`, rounded up.
    /// Returns 0 if `x` is zero.
    function log2Up(uint256 x) internal pure returns (uint256 r) {
        r = log2(x);
        /// @solidity memory-safe-assembly
        assembly {
            r := add(r, lt(shl(r, 1), x))
        }
    }

    /// @dev Returns the log10 of `x`.
    /// Returns 0 if `x` is zero.
    function log10(uint256 x) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(lt(x, 100000000000000000000000000000000000000)) {
                x := div(x, 100000000000000000000000000000000000000)
                r := 38
            }
            if iszero(lt(x, 100000000000000000000)) {
                x := div(x, 100000000000000000000)
                r := add(r, 20)
            }
            if iszero(lt(x, 10000000000)) {
                x := div(x, 10000000000)
                r := add(r, 10)
            }
            if iszero(lt(x, 100000)) {
                x := div(x, 100000)
                r := add(r, 5)
            }
            r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999)))))
        }
    }

    /// @dev Returns the log10 of `x`, rounded up.
    /// Returns 0 if `x` is zero.
    function log10Up(uint256 x) internal pure returns (uint256 r) {
        r = log10(x);
        /// @solidity memory-safe-assembly
        assembly {
            r := add(r, lt(exp(10, r), x))
        }
    }

    /// @dev Returns the log256 of `x`.
    /// Returns 0 if `x` is zero.
    function log256(uint256 x) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(shr(3, r), lt(0xff, shr(r, x)))
        }
    }

    /// @dev Returns the log256 of `x`, rounded up.
    /// Returns 0 if `x` is zero.
    function log256Up(uint256 x) internal pure returns (uint256 r) {
        r = log256(x);
        /// @solidity memory-safe-assembly
        assembly {
            r := add(r, lt(shl(shl(3, r), 1), x))
        }
    }

    /// @dev Returns the scientific notation format `mantissa * 10 ** exponent` of `x`.
    /// Useful for compressing prices (e.g. using 25 bit mantissa and 7 bit exponent).
    function sci(uint256 x) internal pure returns (uint256 mantissa, uint256 exponent) {
        /// @solidity memory-safe-assembly
        assembly {
            mantissa := x
            if mantissa {
                if iszero(mod(mantissa, 1000000000000000000000000000000000)) {
                    mantissa := div(mantissa, 1000000000000000000000000000000000)
                    exponent := 33
                }
                if iszero(mod(mantissa, 10000000000000000000)) {
                    mantissa := div(mantissa, 10000000000000000000)
                    exponent := add(exponent, 19)
                }
                if iszero(mod(mantissa, 1000000000000)) {
                    mantissa := div(mantissa, 1000000000000)
                    exponent := add(exponent, 12)
                }
                if iszero(mod(mantissa, 1000000)) {
                    mantissa := div(mantissa, 1000000)
                    exponent := add(exponent, 6)
                }
                if iszero(mod(mantissa, 10000)) {
                    mantissa := div(mantissa, 10000)
                    exponent := add(exponent, 4)
                }
                if iszero(mod(mantissa, 100)) {
                    mantissa := div(mantissa, 100)
                    exponent := add(exponent, 2)
                }
                if iszero(mod(mantissa, 10)) {
                    mantissa := div(mantissa, 10)
                    exponent := add(exponent, 1)
                }
            }
        }
    }

    /// @dev Convenience function for packing `x` into a smaller number using `sci`.
    /// The `mantissa` will be in bits [7..255] (the upper 249 bits).
    /// The `exponent` will be in bits [0..6] (the lower 7 bits).
    /// Use `SafeCastLib` to safely ensure that the `packed` number is small
    /// enough to fit in the desired unsigned integer type:
    /// ```
    ///     uint32 packed = SafeCastLib.toUint32(FixedPointMathLib.packSci(777 ether));
    /// ```
    function packSci(uint256 x) internal pure returns (uint256 packed) {
        (x, packed) = sci(x); // Reuse for `mantissa` and `exponent`.
        /// @solidity memory-safe-assembly
        assembly {
            if shr(249, x) {
                mstore(0x00, 0xce30380c) // `MantissaOverflow()`.
                revert(0x1c, 0x04)
            }
            packed := or(shl(7, x), packed)
        }
    }

    /// @dev Convenience function for unpacking a packed number from `packSci`.
    function unpackSci(uint256 packed) internal pure returns (uint256 unpacked) {
        unchecked {
            unpacked = (packed >> 7) * 10 ** (packed & 0x7f);
        }
    }

    /// @dev Returns the average of `x` and `y`. Rounds towards zero.
    function avg(uint256 x, uint256 y) internal pure returns (uint256 z) {
        unchecked {
            z = (x & y) + ((x ^ y) >> 1);
        }
    }

    /// @dev Returns the average of `x` and `y`. Rounds towards negative infinity.
    function avg(int256 x, int256 y) internal pure returns (int256 z) {
        unchecked {
            z = (x >> 1) + (y >> 1) + (x & y & 1);
        }
    }

    /// @dev Returns the absolute value of `x`.
    function abs(int256 x) internal pure returns (uint256 z) {
        unchecked {
            z = (uint256(x) + uint256(x >> 255)) ^ uint256(x >> 255);
        }
    }

    /// @dev Returns the absolute distance between `x` and `y`.
    function dist(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := add(xor(sub(0, gt(x, y)), sub(y, x)), gt(x, y))
        }
    }

    /// @dev Returns the absolute distance between `x` and `y`.
    function dist(int256 x, int256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := add(xor(sub(0, sgt(x, y)), sub(y, x)), sgt(x, y))
        }
    }

    /// @dev Returns the minimum of `x` and `y`.
    function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, y), lt(y, x)))
        }
    }

    /// @dev Returns the minimum of `x` and `y`.
    function min(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, y), slt(y, x)))
        }
    }

    /// @dev Returns the maximum of `x` and `y`.
    function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, y), gt(y, x)))
        }
    }

    /// @dev Returns the maximum of `x` and `y`.
    function max(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, y), sgt(y, x)))
        }
    }

    /// @dev Returns `x`, bounded to `minValue` and `maxValue`.
    function clamp(uint256 x, uint256 minValue, uint256 maxValue)
        internal
        pure
        returns (uint256 z)
    {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, minValue), gt(minValue, x)))
            z := xor(z, mul(xor(z, maxValue), lt(maxValue, z)))
        }
    }

    /// @dev Returns `x`, bounded to `minValue` and `maxValue`.
    function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, minValue), sgt(minValue, x)))
            z := xor(z, mul(xor(z, maxValue), slt(maxValue, z)))
        }
    }

    /// @dev Returns greatest common divisor of `x` and `y`.
    function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            for { z := x } y {} {
                let t := y
                y := mod(z, y)
                z := t
            }
        }
    }

    /// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`,
    /// with `t` clamped between `begin` and `end` (inclusive).
    /// Agnostic to the order of (`a`, `b`) and (`end`, `begin`).
    /// If `begins == end`, returns `t <= begin ? a : b`.
    function lerp(uint256 a, uint256 b, uint256 t, uint256 begin, uint256 end)
        internal
        pure
        returns (uint256)
    {
        if (begin > end) (t, begin, end) = (~t, ~begin, ~end);
        if (t <= begin) return a;
        if (t >= end) return b;
        unchecked {
            if (b >= a) return a + fullMulDiv(b - a, t - begin, end - begin);
            return a - fullMulDiv(a - b, t - begin, end - begin);
        }
    }

    /// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`.
    /// with `t` clamped between `begin` and `end` (inclusive).
    /// Agnostic to the order of (`a`, `b`) and (`end`, `begin`).
    /// If `begins == end`, returns `t <= begin ? a : b`.
    function lerp(int256 a, int256 b, int256 t, int256 begin, int256 end)
        internal
        pure
        returns (int256)
    {
        if (begin > end) (t, begin, end) = (~t, ~begin, ~end);
        if (t <= begin) return a;
        if (t >= end) return b;
        // forgefmt: disable-next-item
        unchecked {
            if (b >= a) return int256(uint256(a) + fullMulDiv(uint256(b - a),
                uint256(t - begin), uint256(end - begin)));
            return int256(uint256(a) - fullMulDiv(uint256(a - b),
                uint256(t - begin), uint256(end - begin)));
        }
    }

    /// @dev Returns if `x` is an even number. Some people may need this.
    function isEven(uint256 x) internal pure returns (bool) {
        return x & uint256(1) == uint256(0);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   RAW NUMBER OPERATIONS                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns `x + y`, without checking for overflow.
    function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) {
        unchecked {
            z = x + y;
        }
    }

    /// @dev Returns `x + y`, without checking for overflow.
    function rawAdd(int256 x, int256 y) internal pure returns (int256 z) {
        unchecked {
            z = x + y;
        }
    }

    /// @dev Returns `x - y`, without checking for underflow.
    function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        unchecked {
            z = x - y;
        }
    }

    /// @dev Returns `x - y`, without checking for underflow.
    function rawSub(int256 x, int256 y) internal pure returns (int256 z) {
        unchecked {
            z = x - y;
        }
    }

    /// @dev Returns `x * y`, without checking for overflow.
    function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        unchecked {
            z = x * y;
        }
    }

    /// @dev Returns `x * y`, without checking for overflow.
    function rawMul(int256 x, int256 y) internal pure returns (int256 z) {
        unchecked {
            z = x * y;
        }
    }

    /// @dev Returns `x / y`, returning 0 if `y` is zero.
    function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := div(x, y)
        }
    }

    /// @dev Returns `x / y`, returning 0 if `y` is zero.
    function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := sdiv(x, y)
        }
    }

    /// @dev Returns `x % y`, returning 0 if `y` is zero.
    function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mod(x, y)
        }
    }

    /// @dev Returns `x % y`, returning 0 if `y` is zero.
    function rawSMod(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := smod(x, y)
        }
    }

    /// @dev Returns `(x + y) % d`, return 0 if `d` if zero.
    function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := addmod(x, y, d)
        }
    }

    /// @dev Returns `(x * y) % d`, return 0 if `d` if zero.
    function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mulmod(x, y, d)
        }
    }
}

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

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @author Permit2 operations from (https://github.com/Uniswap/permit2/blob/main/src/libraries/Permit2Lib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.
library SafeTransferLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ETH transfer has failed.
    error ETHTransferFailed();

    /// @dev The ERC20 `transferFrom` has failed.
    error TransferFromFailed();

    /// @dev The ERC20 `transfer` has failed.
    error TransferFailed();

    /// @dev The ERC20 `approve` has failed.
    error ApproveFailed();

    /// @dev The ERC20 `totalSupply` query has failed.
    error TotalSupplyQueryFailed();

    /// @dev The Permit2 operation has failed.
    error Permit2Failed();

    /// @dev The Permit2 amount must be less than `2**160 - 1`.
    error Permit2AmountOverflow();

    /// @dev The Permit2 approve operation has failed.
    error Permit2ApproveFailed();

    /// @dev The Permit2 lockdown operation has failed.
    error Permit2LockdownFailed();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.
    uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;

    /// @dev Suggested gas stipend for contract receiving ETH to perform a few
    /// storage reads and writes, but low enough to prevent griefing.
    uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;

    /// @dev The unique EIP-712 domain separator for the DAI token contract.
    bytes32 internal constant DAI_DOMAIN_SEPARATOR =
        0xdbb8cf42e1ecb028be3f3dbc922e1d878b963f411dc388ced501601c60f7c6f7;

    /// @dev The address for the WETH9 contract on Ethereum mainnet.
    address internal constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;

    /// @dev The canonical Permit2 address.
    /// [Github](https://github.com/Uniswap/permit2)
    /// [Etherscan](https://etherscan.io/address/0x000000000022D473030F116dDEE9F6B43aC78BA3)
    address internal constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       ETH OPERATIONS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.
    //
    // The regular variants:
    // - Forwards all remaining gas to the target.
    // - Reverts if the target reverts.
    // - Reverts if the current contract has insufficient balance.
    //
    // The force variants:
    // - Forwards with an optional gas stipend
    //   (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).
    // - If the target reverts, or if the gas stipend is exhausted,
    //   creates a temporary contract to force send the ETH via `SELFDESTRUCT`.
    //   Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.
    // - Reverts if the current contract has insufficient balance.
    //
    // The try variants:
    // - Forwards with a mandatory gas stipend.
    // - Instead of reverting, returns whether the transfer succeeded.

    /// @dev Sends `amount` (in wei) ETH to `to`.
    function safeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`.
    function safeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // Transfer all the ETH and check if it succeeded or not.
            if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // forgefmt: disable-next-item
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function trySafeTransferAllETH(address to, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      ERC20 OPERATIONS                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for
    /// the current contract to manage.
    function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            let success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                    mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    ///
    /// The `from` account must have at least `amount` approved for the current contract to manage.
    function trySafeTransferFrom(address token, address from, address to, uint256 amount)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                success := lt(or(iszero(extcodesize(token)), returndatasize()), success)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends all of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have their entire balance approved for the current contract to manage.
    function safeTransferAllFrom(address token, address from, address to)
        internal
        returns (uint256 amount)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.
            amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.
            // Perform the transfer, reverting upon failure.
            let success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                    mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransfer(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                    mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sends all of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransferAll(address token, address to) internal returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
            mstore(0x20, address()) // Store the address of the current contract.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x14, to) // Store the `to` argument.
            amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                    mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// Reverts upon failure.
    function safeApprove(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                    mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
    /// then retries the approval again (some tokens, e.g. USDT, requires this).
    /// Reverts upon failure.
    function safeApproveWithRetry(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, retrying upon failure.
            let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                    mstore(0x34, 0) // Store 0 for the `amount`.
                    mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
                    pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.
                    mstore(0x34, amount) // Store back the original `amount`.
                    // Retry the approval, reverting upon failure.
                    success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                    if iszero(and(eq(mload(0x00), 1), success)) {
                        // Check the `extcodesize` again just in case the token selfdestructs lol.
                        if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                            mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                            revert(0x1c, 0x04)
                        }
                    }
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Returns the amount of ERC20 `token` owned by `account`.
    /// Returns zero if the `token` does not exist.
    function balanceOf(address token, address account) internal view returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, account) // Store the `account` argument.
            mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            amount :=
                mul( // The arguments of `mul` are evaluated from right to left.
                    mload(0x20),
                    and( // The arguments of `and` are evaluated from right to left.
                        gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                        staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
                    )
                )
        }
    }

    /// @dev Performs a `token.balanceOf(account)` check.
    /// `implemented` denotes whether the `token` does not implement `balanceOf`.
    /// `amount` is zero if the `token` does not implement `balanceOf`.
    function checkBalanceOf(address token, address account)
        internal
        view
        returns (bool implemented, uint256 amount)
    {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, account) // Store the `account` argument.
            mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            implemented :=
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
                )
            amount := mul(mload(0x20), implemented)
        }
    }

    /// @dev Returns the total supply of the `token`.
    /// Reverts if the token does not exist or does not implement `totalSupply()`.
    function totalSupply(address token) internal view returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x18160ddd) // `totalSupply()`.
            if iszero(
                and(gt(returndatasize(), 0x1f), staticcall(gas(), token, 0x1c, 0x04, 0x00, 0x20))
            ) {
                mstore(0x00, 0x54cd9435) // `TotalSupplyQueryFailed()`.
                revert(0x1c, 0x04)
            }
            result := mload(0x00)
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// If the initial attempt fails, try to use Permit2 to transfer the token.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for the current contract to manage.
    function safeTransferFrom2(address token, address from, address to, uint256 amount) internal {
        if (!trySafeTransferFrom(token, from, to, amount)) {
            permit2TransferFrom(token, from, to, amount);
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to` via Permit2.
    /// Reverts upon failure.
    function permit2TransferFrom(address token, address from, address to, uint256 amount)
        internal
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(add(m, 0x74), shr(96, shl(96, token)))
            mstore(add(m, 0x54), amount)
            mstore(add(m, 0x34), to)
            mstore(add(m, 0x20), shl(96, from))
            // `transferFrom(address,address,uint160,address)`.
            mstore(m, 0x36c78516000000000000000000000000)
            let p := PERMIT2
            let exists := eq(chainid(), 1)
            if iszero(exists) { exists := iszero(iszero(extcodesize(p))) }
            if iszero(
                and(
                    call(gas(), p, 0, add(m, 0x10), 0x84, codesize(), 0x00),
                    lt(iszero(extcodesize(token)), exists) // Token has code and Permit2 exists.
                )
            ) {
                mstore(0x00, 0x7939f4248757f0fd) // `TransferFromFailed()` or `Permit2AmountOverflow()`.
                revert(add(0x18, shl(2, iszero(iszero(shr(160, amount))))), 0x04)
            }
        }
    }

    /// @dev Permit a user to spend a given amount of
    /// another user's tokens via native EIP-2612 permit if possible, falling
    /// back to Permit2 if native permit fails or is not implemented on the token.
    function permit2(
        address token,
        address owner,
        address spender,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        bool success;
        /// @solidity memory-safe-assembly
        assembly {
            for {} shl(96, xor(token, WETH9)) {} {
                mstore(0x00, 0x3644e515) // `DOMAIN_SEPARATOR()`.
                if iszero(
                    and( // The arguments of `and` are evaluated from right to left.
                        lt(iszero(mload(0x00)), eq(returndatasize(), 0x20)), // Returns 1 non-zero word.
                        // Gas stipend to limit gas burn for tokens that don't refund gas when
                        // an non-existing function is called. 5K should be enough for a SLOAD.
                        staticcall(5000, token, 0x1c, 0x04, 0x00, 0x20)
                    )
                ) { break }
                // After here, we can be sure that token is a contract.
                let m := mload(0x40)
                mstore(add(m, 0x34), spender)
                mstore(add(m, 0x20), shl(96, owner))
                mstore(add(m, 0x74), deadline)
                if eq(mload(0x00), DAI_DOMAIN_SEPARATOR) {
                    mstore(0x14, owner)
                    mstore(0x00, 0x7ecebe00000000000000000000000000) // `nonces(address)`.
                    mstore(
                        add(m, 0x94),
                        lt(iszero(amount), staticcall(gas(), token, 0x10, 0x24, add(m, 0x54), 0x20))
                    )
                    mstore(m, 0x8fcbaf0c000000000000000000000000) // `IDAIPermit.permit`.
                    // `nonces` is already at `add(m, 0x54)`.
                    // `amount != 0` is already stored at `add(m, 0x94)`.
                    mstore(add(m, 0xb4), and(0xff, v))
                    mstore(add(m, 0xd4), r)
                    mstore(add(m, 0xf4), s)
                    success := call(gas(), token, 0, add(m, 0x10), 0x104, codesize(), 0x00)
                    break
                }
                mstore(m, 0xd505accf000000000000000000000000) // `IERC20Permit.permit`.
                mstore(add(m, 0x54), amount)
                mstore(add(m, 0x94), and(0xff, v))
                mstore(add(m, 0xb4), r)
                mstore(add(m, 0xd4), s)
                success := call(gas(), token, 0, add(m, 0x10), 0xe4, codesize(), 0x00)
                break
            }
        }
        if (!success) simplePermit2(token, owner, spender, amount, deadline, v, r, s);
    }

    /// @dev Simple permit on the Permit2 contract.
    function simplePermit2(
        address token,
        address owner,
        address spender,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, 0x927da105) // `allowance(address,address,address)`.
            {
                let addressMask := shr(96, not(0))
                mstore(add(m, 0x20), and(addressMask, owner))
                mstore(add(m, 0x40), and(addressMask, token))
                mstore(add(m, 0x60), and(addressMask, spender))
                mstore(add(m, 0xc0), and(addressMask, spender))
            }
            let p := mul(PERMIT2, iszero(shr(160, amount)))
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x5f), // Returns 3 words: `amount`, `expiration`, `nonce`.
                    staticcall(gas(), p, add(m, 0x1c), 0x64, add(m, 0x60), 0x60)
                )
            ) {
                mstore(0x00, 0x6b836e6b8757f0fd) // `Permit2Failed()` or `Permit2AmountOverflow()`.
                revert(add(0x18, shl(2, iszero(p))), 0x04)
            }
            mstore(m, 0x2b67b570) // `Permit2.permit` (PermitSingle variant).
            // `owner` is already `add(m, 0x20)`.
            // `token` is already at `add(m, 0x40)`.
            mstore(add(m, 0x60), amount)
            mstore(add(m, 0x80), 0xffffffffffff) // `expiration = type(uint48).max`.
            // `nonce` is already at `add(m, 0xa0)`.
            // `spender` is already at `add(m, 0xc0)`.
            mstore(add(m, 0xe0), deadline)
            mstore(add(m, 0x100), 0x100) // `signature` offset.
            mstore(add(m, 0x120), 0x41) // `signature` length.
            mstore(add(m, 0x140), r)
            mstore(add(m, 0x160), s)
            mstore(add(m, 0x180), shl(248, v))
            if iszero( // Revert if token does not have code, or if the call fails.
            mul(extcodesize(token), call(gas(), p, 0, add(m, 0x1c), 0x184, codesize(), 0x00))) {
                mstore(0x00, 0x6b836e6b) // `Permit2Failed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Approves `spender` to spend `amount` of `token` for `address(this)`.
    function permit2Approve(address token, address spender, uint160 amount, uint48 expiration)
        internal
    {
        /// @solidity memory-safe-assembly
        assembly {
            let addressMask := shr(96, not(0))
            let m := mload(0x40)
            mstore(m, 0x87517c45) // `approve(address,address,uint160,uint48)`.
            mstore(add(m, 0x20), and(addressMask, token))
            mstore(add(m, 0x40), and(addressMask, spender))
            mstore(add(m, 0x60), and(addressMask, amount))
            mstore(add(m, 0x80), and(0xffffffffffff, expiration))
            if iszero(call(gas(), PERMIT2, 0, add(m, 0x1c), 0xa0, codesize(), 0x00)) {
                mstore(0x00, 0x324f14ae) // `Permit2ApproveFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Revokes an approval for `token` and `spender` for `address(this)`.
    function permit2Lockdown(address token, address spender) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, 0xcc53287f) // `Permit2.lockdown`.
            mstore(add(m, 0x20), 0x20) // Offset of the `approvals`.
            mstore(add(m, 0x40), 1) // `approvals.length`.
            mstore(add(m, 0x60), shr(96, shl(96, token)))
            mstore(add(m, 0x80), shr(96, shl(96, spender)))
            if iszero(call(gas(), PERMIT2, 0, add(m, 0x1c), 0xa0, codesize(), 0x00)) {
                mstore(0x00, 0x96b3de23) // `Permit2LockdownFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }
}

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

/// @notice Signature verification helper that supports both ECDSA signatures from EOAs
/// and ERC1271 signatures from smart contract wallets like Argent and Gnosis safe.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SignatureCheckerLib.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/SignatureChecker.sol)
///
/// @dev Note:
/// - The signature checking functions use the ecrecover precompile (0x1).
/// - The `bytes memory signature` variants use the identity precompile (0x4)
///   to copy memory internally.
/// - Unlike ECDSA signatures, contract signatures are revocable.
/// - As of Solady version 0.0.134, all `bytes signature` variants accept both
///   regular 65-byte `(r, s, v)` and EIP-2098 `(r, vs)` short form signatures.
///   See: https://eips.ethereum.org/EIPS/eip-2098
///   This is for calldata efficiency on smart accounts prevalent on L2s.
///
/// WARNING! Do NOT use signatures as unique identifiers:
/// - Use a nonce in the digest to prevent replay attacks on the same contract.
/// - Use EIP-712 for the digest to prevent replay attacks across different chains and contracts.
///   EIP-712 also enables readable signing of typed data for better user safety.
/// This implementation does NOT check if a signature is non-malleable.
library SignatureCheckerLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*               SIGNATURE CHECKING OPERATIONS                */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns whether `signature` is valid for `signer` and `hash`.
    /// If `signer.code.length == 0`, then validate with `ecrecover`, else
    /// it will validate with ERC1271 on `signer`.
    function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature)
        internal
        view
        returns (bool isValid)
    {
        if (signer == address(0)) return isValid;
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            for {} 1 {} {
                if iszero(extcodesize(signer)) {
                    switch mload(signature)
                    case 64 {
                        let vs := mload(add(signature, 0x40))
                        mstore(0x20, add(shr(255, vs), 27)) // `v`.
                        mstore(0x60, shr(1, shl(1, vs))) // `s`.
                    }
                    case 65 {
                        mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
                        mstore(0x60, mload(add(signature, 0x40))) // `s`.
                    }
                    default { break }
                    mstore(0x00, hash)
                    mstore(0x40, mload(add(signature, 0x20))) // `r`.
                    let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
                    isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))
                    mstore(0x60, 0) // Restore the zero slot.
                    mstore(0x40, m) // Restore the free memory pointer.
                    break
                }
                let f := shl(224, 0x1626ba7e)
                mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
                mstore(add(m, 0x04), hash)
                let d := add(m, 0x24)
                mstore(d, 0x40) // The offset of the `signature` in the calldata.
                // Copy the `signature` over.
                let n := add(0x20, mload(signature))
                let copied := staticcall(gas(), 4, signature, n, add(m, 0x44), n)
                isValid := staticcall(gas(), signer, m, add(returndatasize(), 0x44), d, 0x20)
                isValid := and(eq(mload(d), f), and(isValid, copied))
                break
            }
        }
    }

    /// @dev Returns whether `signature` is valid for `signer` and `hash`.
    /// If `signer.code.length == 0`, then validate with `ecrecover`, else
    /// it will validate with ERC1271 on `signer`.
    function isValidSignatureNowCalldata(address signer, bytes32 hash, bytes calldata signature)
        internal
        view
        returns (bool isValid)
    {
        if (signer == address(0)) return isValid;
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            for {} 1 {} {
                if iszero(extcodesize(signer)) {
                    switch signature.length
                    case 64 {
                        let vs := calldataload(add(signature.offset, 0x20))
                        mstore(0x20, add(shr(255, vs), 27)) // `v`.
                        mstore(0x40, calldataload(signature.offset)) // `r`.
                        mstore(0x60, shr(1, shl(1, vs))) // `s`.
                    }
                    case 65 {
                        mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
                        calldatacopy(0x40, signature.offset, 0x40) // `r`, `s`.
                    }
                    default { break }
                    mstore(0x00, hash)
                    let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
                    isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))
                    mstore(0x60, 0) // Restore the zero slot.
                    mstore(0x40, m) // Restore the free memory pointer.
                    break
                }
                let f := shl(224, 0x1626ba7e)
                mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
                mstore(add(m, 0x04), hash)
                let d := add(m, 0x24)
                mstore(d, 0x40) // The offset of the `signature` in the calldata.
                mstore(add(m, 0x44), signature.length)
                // Copy the `signature` over.
                calldatacopy(add(m, 0x64), signature.offset, signature.length)
                isValid := staticcall(gas(), signer, m, add(signature.length, 0x64), d, 0x20)
                isValid := and(eq(mload(d), f), isValid)
                break
            }
        }
    }

    /// @dev Returns whether the signature (`r`, `vs`) is valid for `signer` and `hash`.
    /// If `signer.code.length == 0`, then validate with `ecrecover`, else
    /// it will validate with ERC1271 on `signer`.
    function isValidSignatureNow(address signer, bytes32 hash, bytes32 r, bytes32 vs)
        internal
        view
        returns (bool isValid)
    {
        if (signer == address(0)) return isValid;
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            for {} 1 {} {
                if iszero(extcodesize(signer)) {
                    mstore(0x00, hash)
                    mstore(0x20, add(shr(255, vs), 27)) // `v`.
                    mstore(0x40, r) // `r`.
                    mstore(0x60, shr(1, shl(1, vs))) // `s`.
                    let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
                    isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))
                    mstore(0x60, 0) // Restore the zero slot.
                    mstore(0x40, m) // Restore the free memory pointer.
                    break
                }
                let f := shl(224, 0x1626ba7e)
                mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
                mstore(add(m, 0x04), hash)
                let d := add(m, 0x24)
                mstore(d, 0x40) // The offset of the `signature` in the calldata.
                mstore(add(m, 0x44), 65) // Length of the signature.
                mstore(add(m, 0x64), r) // `r`.
                mstore(add(m, 0x84), shr(1, shl(1, vs))) // `s`.
                mstore8(add(m, 0xa4), add(shr(255, vs), 27)) // `v`.
                isValid := staticcall(gas(), signer, m, 0xa5, d, 0x20)
                isValid := and(eq(mload(d), f), isValid)
                break
            }
        }
    }

    /// @dev Returns whether the signature (`v`, `r`, `s`) is valid for `signer` and `hash`.
    /// If `signer.code.length == 0`, then validate with `ecrecover`, else
    /// it will validate with ERC1271 on `signer`.
    function isValidSignatureNow(address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s)
        internal
        view
        returns (bool isValid)
    {
        if (signer == address(0)) return isValid;
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            for {} 1 {} {
                if iszero(extcodesize(signer)) {
                    mstore(0x00, hash)
                    mstore(0x20, and(v, 0xff)) // `v`.
                    mstore(0x40, r) // `r`.
                    mstore(0x60, s) // `s`.
                    let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
                    isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))
                    mstore(0x60, 0) // Restore the zero slot.
                    mstore(0x40, m) // Restore the free memory pointer.
                    break
                }
                let f := shl(224, 0x1626ba7e)
                mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
                mstore(add(m, 0x04), hash)
                let d := add(m, 0x24)
                mstore(d, 0x40) // The offset of the `signature` in the calldata.
                mstore(add(m, 0x44), 65) // Length of the signature.
                mstore(add(m, 0x64), r) // `r`.
                mstore(add(m, 0x84), s) // `s`.
                mstore8(add(m, 0xa4), v) // `v`.
                isValid := staticcall(gas(), signer, m, 0xa5, d, 0x20)
                isValid := and(eq(mload(d), f), isValid)
                break
            }
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     ERC1271 OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // Note: These ERC1271 operations do NOT have an ECDSA fallback.

    /// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract.
    function isValidERC1271SignatureNow(address signer, bytes32 hash, bytes memory signature)
        internal
        view
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let f := shl(224, 0x1626ba7e)
            mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
            mstore(add(m, 0x04), hash)
            let d := add(m, 0x24)
            mstore(d, 0x40) // The offset of the `signature` in the calldata.
            // Copy the `signature` over.
            let n := add(0x20, mload(signature))
            let copied := staticcall(gas(), 4, signature, n, add(m, 0x44), n)
            isValid := staticcall(gas(), signer, m, add(returndatasize(), 0x44), d, 0x20)
            isValid := and(eq(mload(d), f), and(isValid, copied))
        }
    }

    /// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract.
    function isValidERC1271SignatureNowCalldata(
        address signer,
        bytes32 hash,
        bytes calldata signature
    ) internal view returns (bool isValid) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let f := shl(224, 0x1626ba7e)
            mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
            mstore(add(m, 0x04), hash)
            let d := add(m, 0x24)
            mstore(d, 0x40) // The offset of the `signature` in the calldata.
            mstore(add(m, 0x44), signature.length)
            // Copy the `signature` over.
            calldatacopy(add(m, 0x64), signature.offset, signature.length)
            isValid := staticcall(gas(), signer, m, add(signature.length, 0x64), d, 0x20)
            isValid := and(eq(mload(d), f), isValid)
        }
    }

    /// @dev Returns whether the signature (`r`, `vs`) is valid for `hash`
    /// for an ERC1271 `signer` contract.
    function isValidERC1271SignatureNow(address signer, bytes32 hash, bytes32 r, bytes32 vs)
        internal
        view
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let f := shl(224, 0x1626ba7e)
            mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
            mstore(add(m, 0x04), hash)
            let d := add(m, 0x24)
            mstore(d, 0x40) // The offset of the `signature` in the calldata.
            mstore(add(m, 0x44), 65) // Length of the signature.
            mstore(add(m, 0x64), r) // `r`.
            mstore(add(m, 0x84), shr(1, shl(1, vs))) // `s`.
            mstore8(add(m, 0xa4), add(shr(255, vs), 27)) // `v`.
            isValid := staticcall(gas(), signer, m, 0xa5, d, 0x20)
            isValid := and(eq(mload(d), f), isValid)
        }
    }

    /// @dev Returns whether the signature (`v`, `r`, `s`) is valid for `hash`
    /// for an ERC1271 `signer` contract.
    function isValidERC1271SignatureNow(address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s)
        internal
        view
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            let f := shl(224, 0x1626ba7e)
            mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
            mstore(add(m, 0x04), hash)
            let d := add(m, 0x24)
            mstore(d, 0x40) // The offset of the `signature` in the calldata.
            mstore(add(m, 0x44), 65) // Length of the signature.
            mstore(add(m, 0x64), r) // `r`.
            mstore(add(m, 0x84), s) // `s`.
            mstore8(add(m, 0xa4), v) // `v`.
            isValid := staticcall(gas(), signer, m, 0xa5, d, 0x20)
            isValid := and(eq(mload(d), f), isValid)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     ERC6492 OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // Note: These ERC6492 operations now include an ECDSA fallback at the very end.
    // The calldata variants are excluded for brevity.

    /// @dev Returns whether `signature` is valid for `hash`.
    /// If the signature is postfixed with the ERC6492 magic number, it will attempt to
    /// deploy / prepare the `signer` smart account before doing a regular ERC1271 check.
    /// Note: This function is NOT reentrancy safe.
    /// The verifier must be deployed.
    /// Otherwise, the function will return false if `signer` is not yet deployed / prepared.
    /// See: https://gist.github.com/Vectorized/011d6becff6e0a73e42fe100f8d7ef04
    /// With a dedicated verifier, this function is safe to use in contracts
    /// that have been granted special permissions.
    function isValidERC6492SignatureNowAllowSideEffects(
        address signer,
        bytes32 hash,
        bytes memory signature
    ) internal returns (bool isValid) {
        /// @solidity memory-safe-assembly
        assembly {
            function callIsValidSignature(signer_, hash_, signature_) -> _isValid {
                let m_ := mload(0x40)
                let f_ := shl(224, 0x1626ba7e)
                mstore(m_, f_) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
                mstore(add(m_, 0x04), hash_)
                let d_ := add(m_, 0x24)
                mstore(d_, 0x40) // The offset of the `signature` in the calldata.
                let n_ := add(0x20, mload(signature_))
                let copied_ := staticcall(gas(), 4, signature_, n_, add(m_, 0x44), n_)
                _isValid := staticcall(gas(), signer_, m_, add(returndatasize(), 0x44), d_, 0x20)
                _isValid := and(eq(mload(d_), f_), and(_isValid, copied_))
            }
            let noCode := iszero(extcodesize(signer))
            let n := mload(signature)
            for {} 1 {} {
                if iszero(eq(mload(add(signature, n)), mul(0x6492, div(not(isValid), 0xffff)))) {
                    if iszero(noCode) { isValid := callIsValidSignature(signer, hash, signature) }
                    break
                }
                if iszero(noCode) {
                    let o := add(signature, 0x20) // Signature bytes.
                    isValid := callIsValidSignature(signer, hash, add(o, mload(add(o, 0x40))))
                    if isValid { break }
                }
                let m := mload(0x40)
                mstore(m, signer)
                mstore(add(m, 0x20), hash)
                pop(
                    call(
                        gas(), // Remaining gas.
                        0x0000bc370E4DC924F427d84e2f4B9Ec81626ba7E, // Non-reverting verifier.
                        0, // Send zero ETH.
                        m, // Start of memory.
                        add(returndatasize(), 0x40), // Length of calldata in memory.
                        staticcall(gas(), 4, add(signature, 0x20), n, add(m, 0x40), n), // 1.
                        0x00 // Length of returndata to write.
                    )
                )
                isValid := returndatasize()
                break
            }
            // Do `ecrecover` fallback if `noCode && !isValid`.
            for {} gt(noCode, isValid) {} {
                switch n
                case 64 {
                    let vs := mload(add(signature, 0x40))
                    mstore(0x20, add(shr(255, vs), 27)) // `v`.
                    mstore(0x60, shr(1, shl(1, vs))) // `s`.
                }
                case 65 {
                    mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
                    mstore(0x60, mload(add(signature, 0x40))) // `s`.
                }
                default { break }
                let m := mload(0x40)
                mstore(0x00, hash)
                mstore(0x40, mload(add(signature, 0x20))) // `r`.
                let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
                isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))
                mstore(0x60, 0) // Restore the zero slot.
                mstore(0x40, m) // Restore the free memory pointer.
                break
            }
        }
    }

    /// @dev Returns whether `signature` is valid for `hash`.
    /// If the signature is postfixed with the ERC6492 magic number, it will attempt
    /// to use a reverting verifier to deploy / prepare the `signer` smart account
    /// and do a `isValidSignature` check via the reverting verifier.
    /// Note: This function is reentrancy safe.
    /// The reverting verifier must be deployed.
    /// Otherwise, the function will return false if `signer` is not yet deployed / prepared.
    /// See: https://gist.github.com/Vectorized/846a474c855eee9e441506676800a9ad
    function isValidERC6492SignatureNow(address signer, bytes32 hash, bytes memory signature)
        internal
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            function callIsValidSignature(signer_, hash_, signature_) -> _isValid {
                let m_ := mload(0x40)
                let f_ := shl(224, 0x1626ba7e)
                mstore(m_, f_) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
                mstore(add(m_, 0x04), hash_)
                let d_ := add(m_, 0x24)
                mstore(d_, 0x40) // The offset of the `signature` in the calldata.
                let n_ := add(0x20, mload(signature_))
                let copied_ := staticcall(gas(), 4, signature_, n_, add(m_, 0x44), n_)
                _isValid := staticcall(gas(), signer_, m_, add(returndatasize(), 0x44), d_, 0x20)
                _isValid := and(eq(mload(d_), f_), and(_isValid, copied_))
            }
            let noCode := iszero(extcodesize(signer))
            let n := mload(signature)
            for {} 1 {} {
                if iszero(eq(mload(add(signature, n)), mul(0x6492, div(not(isValid), 0xffff)))) {
                    if iszero(noCode) { isValid := callIsValidSignature(signer, hash, signature) }
                    break
                }
                if iszero(noCode) {
                    let o := add(signature, 0x20) // Signature bytes.
                    isValid := callIsValidSignature(signer, hash, add(o, mload(add(o, 0x40))))
                    if isValid { break }
                }
                let m := mload(0x40)
                mstore(m, signer)
                mstore(add(m, 0x20), hash)
                let willBeZeroIfRevertingVerifierExists :=
                    call(
                        gas(), // Remaining gas.
                        0x00007bd799e4A591FeA53f8A8a3E9f931626Ba7e, // Reverting verifier.
                        0, // Send zero ETH.
                        m, // Start of memory.
                        add(returndatasize(), 0x40), // Length of calldata in memory.
                        staticcall(gas(), 4, add(signature, 0x20), n, add(m, 0x40), n), // 1.
                        0x00 // Length of returndata to write.
                    )
                isValid := gt(returndatasize(), willBeZeroIfRevertingVerifierExists)
                break
            }
            // Do `ecrecover` fallback if `noCode && !isValid`.
            for {} gt(noCode, isValid) {} {
                switch n
                case 64 {
                    let vs := mload(add(signature, 0x40))
                    mstore(0x20, add(shr(255, vs), 27)) // `v`.
                    mstore(0x60, shr(1, shl(1, vs))) // `s`.
                }
                case 65 {
                    mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
                    mstore(0x60, mload(add(signature, 0x40))) // `s`.
                }
                default { break }
                let m := mload(0x40)
                mstore(0x00, hash)
                mstore(0x40, mload(add(signature, 0x20))) // `r`.
                let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
                isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))
                mstore(0x60, 0) // Restore the zero slot.
                mstore(0x40, m) // Restore the free memory pointer.
                break
            }
        }
    }

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

    /// @dev Returns an Ethereum Signed Message, created from a `hash`.
    /// This produces a hash corresponding to the one signed with the
    /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign)
    /// JSON-RPC method as part of EIP-191.
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x20, hash) // Store into scratch space for keccak256.
            mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes.
            result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`.
        }
    }

    /// @dev Returns an Ethereum Signed Message, created from `s`.
    /// This produces a hash corresponding to the one signed with the
    /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign)
    /// JSON-RPC method as part of EIP-191.
    /// Note: Supports lengths of `s` up to 999999 bytes.
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let sLength := mload(s)
            let o := 0x20
            mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded.
            mstore(0x00, 0x00)
            // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`.
            for { let temp := sLength } 1 {} {
                o := sub(o, 1)
                mstore8(o, add(48, mod(temp, 10)))
                temp := div(temp, 10)
                if iszero(temp) { break }
            }
            let n := sub(0x3a, o) // Header length: `26 + 32 - o`.
            // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes.
            returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20))
            mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header.
            result := keccak256(add(s, sub(0x20, n)), add(n, sLength))
            mstore(s, sLength) // Restore the length.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   EMPTY CALLDATA HELPERS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns an empty calldata bytes.
    function emptySignature() internal pure returns (bytes calldata signature) {
        /// @solidity memory-safe-assembly
        assembly {
            signature.length := 0
        }
    }
}

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

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

/// @title BlockNumberish
/// @custom:security-contact [email protected]
/// A helper contract to get the current block number on different chains
contract BlockNumberish {
    uint256 private constant ARB_CHAIN_ID = 42161;
    address private constant ARB_SYS_ADDRESS = 0x0000000000000000000000000000000000000064;

    function _getBlockNumberish() internal view returns (uint256) {
        // Set the function to use based on chainid
        if (block.chainid == ARB_CHAIN_ID) {
            return IArbSys(ARB_SYS_ADDRESS).arbBlockNumber();
        } else {
            return block.number;
        }
    }
}

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

import {FixedPointMathLib} from "solady/utils/FixedPointMathLib.sol";
import {EfficiencyLib} from "the-compact/src/lib/EfficiencyLib.sol";

/**
 * @title PriceCurveElement
 * @notice Custom type for price curve parameters with bit-packed values.
 * @dev Each element packs two values into a single uint256:
 *      - blockDuration (16 bits): Duration in blocks for this curve segment
 *      - scalingFactor (240 bits): Scaling factor to apply during this segment (1e18 = neutral)
 */
type PriceCurveElement is uint256;

/**
 * @title PriceCurveLib
 * @author 0age
 * @custom:security-contact [email protected]
 * @notice Library for managing time-based price curves in Tribunal auctions.
 * @dev Provides functionality for creating, manipulating, and evaluating price curves that define how
 * auction prices evolve over time. Supports linear interpolation between discrete points, instant price
 * jumps via zero-duration segments, and combining base curves with supplemental adjustments from adjusters.
 * Each PriceCurveElement packs a block duration (16 bits) and scaling factor (240 bits) into a single uint256.
 */
library PriceCurveLib {
    using PriceCurveLib for uint256;
    using FixedPointMathLib for uint256;
    using EfficiencyLib for bool;

    error PriceCurveBlocksExceeded();
    error InvalidPriceCurveParameters();

    // Constants for bit manipulation
    uint256 private constant BLOCK_DURATION_BITS = 16;
    uint256 private constant SCALING_FACTOR_BITS = 240;

    // Bit positions
    uint256 private constant BLOCK_DURATION_SHIFT = SCALING_FACTOR_BITS;

    // Bit masks
    uint256 private constant SCALING_FACTOR_MASK = ((1 << SCALING_FACTOR_BITS) - 1);

    /**
     * @notice Creates a new PriceCurveElement from individual components.
     * @dev Packs the block duration (16 bits) and scaling factor (240 bits) into a single uint256.
     * The scaling factor represents the price multiplier for this segment (1e18 = neutral/100%).
     * @param blockDuration Duration in blocks for this curve segment (16 bits).
     * @param scalingFactor Scaling factor to apply during this segment (240 bits, 1e18 = neutral).
     * @return The packed PriceCurveElement containing both values.
     */
    function create(uint16 blockDuration, uint240 scalingFactor)
        internal
        pure
        returns (PriceCurveElement)
    {
        uint256 packed = (uint256(blockDuration) << BLOCK_DURATION_SHIFT) | uint256(scalingFactor);

        return PriceCurveElement.wrap(packed);
    }

    /**
     * @notice Extracts the block duration from a PriceCurveElement.
     * @dev Unpacks and shifts the upper 16 bits to retrieve the duration value.
     * @param self The PriceCurveElement to extract from.
     * @return The block duration as uint256 (originally 16 bits).
     */
    function getBlockDuration(PriceCurveElement self) internal pure returns (uint256) {
        return PriceCurveElement.unwrap(self) >> BLOCK_DURATION_SHIFT;
    }

    /**
     * @notice Extracts the scaling factor from a PriceCurveElement.
     * @dev Unpacks and masks the lower 240 bits to retrieve the scaling factor value.
     * @param self The PriceCurveElement to extract from.
     * @return The scaling factor as uint256 (originally 240 bits, 1e18 = neutral).
     */
    function getFillIncrease(PriceCurveElement self) internal pure returns (uint256) {
        return PriceCurveElement.unwrap(self) & SCALING_FACTOR_MASK;
    }

    /**
     * @notice Extracts both block duration and scaling factor from a PriceCurveElement in a single call.
     * @dev More gas-efficient than calling getBlockDuration and getFillIncrease separately.
     * Unpacks the uint256 by shifting for duration and masking for scaling factor.
     * @param self The PriceCurveElement to extract from.
     * @return blockDuration The block duration value (originally 16 bits).
     * @return scalingFactor The scaling factor value (originally 240 bits, 1e18 = neutral).
     */
    function getComponents(PriceCurveElement self)
        internal
        pure
        returns (uint256 blockDuration, uint256 scalingFactor)
    {
        uint256 value = PriceCurveElement.unwrap(self);

        blockDuration = value >> BLOCK_DURATION_SHIFT;
        scalingFactor = (value & SCALING_FACTOR_MASK);

        return (blockDuration, scalingFactor);
    }

    /**
     * @notice Combines a base price curve with a supplemental price curve from the adjuster.
     * @dev Applies the adjuster's supplemental curve by adding scaling factors and subtracting 1e18 to maintain
     * proper scaling: combinedScalingFactor = baseScalingFactor + supplementalScalingFactor - 1e18.
     * This allows the adjuster to modify prices dynamically while preserving the sponsor's base curve structure.
     * Validates that both curves scale in the same direction and that combined values don't overflow 240 bits.
     * If supplemental curve is shorter, base curve values are used for remaining segments.
     * @param parameters The base price curve array (calldata).
     * @param supplementalParameters The supplemental price curve array from the adjuster (calldata).
     * @return combinedParameters The combined price curve array with adjusted scaling factors.
     */
    function applySupplementalPriceCurve(
        uint256[] calldata parameters,
        uint256[] calldata supplementalParameters
    ) internal pure returns (uint256[] memory combinedParameters) {
        combinedParameters = new uint256[](parameters.length);
        uint256 errorBuffer = 0;
        uint256 applicationRange = parameters.length.min(supplementalParameters.length);
        for (uint256 i = 0; i < applicationRange; ++i) {
            (uint256 duration, uint256 scalingFactor) =
                getComponents(PriceCurveElement.wrap(parameters[i]));
            uint256 supplementalScalingFactor = supplementalParameters[i];

            uint256 combinedScalingFactor = scalingFactor + supplementalScalingFactor - 1e18;

            errorBuffer |= (!scalingFactor.sharesScalingDirection(supplementalScalingFactor))
            .asUint256() | (combinedScalingFactor > type(uint240).max).asUint256();

            combinedParameters[i] =
                PriceCurveElement.unwrap(create(uint16(duration), uint240(combinedScalingFactor)));
        }

        if (errorBuffer != 0) {
            revert InvalidPriceCurveParameters();
        }

        for (uint256 i = applicationRange; i < parameters.length; ++i) {
            combinedParameters[i] = parameters[i];
        }
    }

    /**
     * @notice Combines a base price curve with a supplemental price curve (memory version).
     * @dev Memory-based variant of applySupplementalPriceCurve for cases where curves are already in memory.
     * Applies the adjuster's supplemental curve by adding scaling factors and subtracting 1e18 to maintain
     * proper scaling: combinedScalingFactor = baseScalingFactor + supplementalScalingFactor - 1e18.
     * Validates that both curves scale in the same direction and that combined values don't overflow 240 bits.
     * If supplemental curve is shorter, base curve values are used for remaining segments.
     * @param parameters The base price curve array (memory).
     * @param supplementalParameters The supplemental price curve array from the adjuster (memory).
     * @return combinedParameters The combined price curve array with adjusted scaling factors.
     */
    function applyMemorySupplementalPriceCurve(
        uint256[] memory parameters,
        uint256[] memory supplementalParameters
    ) internal pure returns (uint256[] memory combinedParameters) {
        combinedParameters = new uint256[](parameters.length);
        uint256 errorBuffer = 0;
        uint256 applicationRange = parameters.length.min(supplementalParameters.length);
        for (uint256 i = 0; i < applicationRange; ++i) {
            (uint256 duration, uint256 scalingFactor) =
                getComponents(PriceCurveElement.wrap(parameters[i]));
            uint256 supplementalScalingFactor = supplementalParameters[i];

            uint256 combinedScalingFactor = scalingFactor + supplementalScalingFactor - 1e18;

            errorBuffer |= (!scalingFactor.sharesScalingDirection(supplementalScalingFactor))
            .asUint256() | (combinedScalingFactor > type(uint240).max).asUint256();

            combinedParameters[i] =
                PriceCurveElement.unwrap(create(uint16(duration), uint240(combinedScalingFactor)));
        }

        if (errorBuffer != 0) {
            revert InvalidPriceCurveParameters();
        }

        for (uint256 i = applicationRange; i < parameters.length; ++i) {
            combinedParameters[i] = parameters[i];
        }
    }

    /**
     * @notice Calculates the current scaling factor based on blocks elapsed since auction start.
     * @dev Processes the price curve array sequentially to determine the current price based on block progression.
     * Supports linear interpolation between discrete curve points for gradual price transitions, and zero-duration
     * segments that enable instant price jumps at specific blocks. The final segment defaults to 1e18 (neutral)
     * if the auction extends beyond the specified curve duration. Reverts if blocks elapsed exceeds total curve duration.
     * @param parameters Array of PriceCurveElements defining the curve segments.
     * @param blocksPassed Number of blocks elapsed since the auction start (targetBlock).
     * @return currentScalingFactor The calculated scaling factor for the current block (1e18 = neutral).
     */
    function getCalculatedValues(uint256[] memory parameters, uint256 blocksPassed)
        internal
        pure
        returns (uint256 currentScalingFactor)
    {
        // Check if there are no parameters
        if (parameters.length == 0) {
            return (1e18);
        }

        uint256 blocksCounted = 0;
        bool hasPassedZeroDuration = false;

        // Process each parameter segment in a single pass
        for (uint256 i = 0; i < parameters.length; i++) {
            // Extract values from current parameter
            (uint256 duration, uint256 scalingFactor) =
                getComponents(PriceCurveElement.wrap(parameters[i]));

            // Special handling for zero duration
            if (duration == 0) {
                // If we've reached or passed this zero duration point
                if (blocksPassed >= blocksCounted) {
                    // Update values to the zero duration values
                    currentScalingFactor = scalingFactor;
                    hasPassedZeroDuration = true;

                    // If we're exactly at this point, return these values
                    if (blocksPassed == blocksCounted) {
                        return scalingFactor;
                    }
                }

                // Continue to the next segment (zero duration doesn't add to blocksCounted)
                continue;
            }

            // If blocksPassed is in this segment
            if (blocksPassed < blocksCounted + duration) {
                // For regular segments, we need to handle based on whether we've passed a zero duration
                if (
                    hasPassedZeroDuration
                        && getBlockDuration(PriceCurveElement.wrap(parameters[i - 1])) == 0
                ) {
                    // We're in a segment right after a zero duration - start interpolation from zero duration values
                    (, uint256 zeroDurationScalingFactor) =
                        getComponents(PriceCurveElement.wrap(parameters[i - 1]));

                    if (!zeroDurationScalingFactor.sharesScalingDirection(scalingFactor)) {
                        revert InvalidPriceCurveParameters();
                    }

                    // Interpolate from zero duration values to current segment values
                    currentScalingFactor = _locateCurrentAmount(
                        zeroDurationScalingFactor,
                        scalingFactor,
                        blocksCounted,
                        blocksPassed,
                        blocksCounted + duration,
                        zeroDurationScalingFactor > 1e18 // Round up for fillIncrease, down for claimDecrease
                    );
                } else {
                    // Standard interpolation between current and next segment
                    uint256 endScalingFactor;

                    if (i + 1 < parameters.length) {
                        // Next segment determines the target values
                        (, endScalingFactor) =
                            getComponents(PriceCurveElement.wrap(parameters[i + 1]));
                    } else {
                        // Last segment ends at 1e18
                        // For exact-in, defaults to decaying fill amount to minFillAmount that the sponsor is willing to accept
                        // For exact-out, default to increasing claim amounts to maximumClaimAmounts that the sponsor is willing to pay
                        endScalingFactor = 1e18;
                    }

                    if (!scalingFactor.sharesScalingDirection(endScalingFactor)) {
                        revert InvalidPriceCurveParameters();
                    }

                    // Use the provided interpolation function
                    currentScalingFactor = _locateCurrentAmount(
                        scalingFactor,
                        endScalingFactor,
                        blocksCounted,
                        blocksPassed,
                        blocksCounted + duration,
                        scalingFactor > 1e18 // Round up for fillIncrease, down for claimDecrease
                    );
                }

                return (currentScalingFactor);
            }

            // We've passed this segment, update our tracking
            blocksCounted += duration;
        }

        // If we went through all segments and exceeded total blocks, revert
        if (blocksPassed >= blocksCounted) {
            revert PriceCurveBlocksExceeded();
        }

        // This should never be reached
        return (0);
    }

    /**
     * @notice Performs linear interpolation to derive the current scaling factor between two points.
     * @dev Private pure function that interpolates between start and end amounts based on block progression.
     * If start and end amounts are equal, returns the end amount without calculation. Otherwise, performs
     * weighted interpolation: ((startAmount × remaining) + (endAmount × elapsed)) / duration.
     * The roundUp parameter controls rounding direction: up for exact-in mode (increasing fills), down for
     * exact-out mode (decreasing claims).
     * IMPORTANT: This function expects startBlock ≤ currentBlock < endBlock; violating this causes underflow.
     * @param startAmount The starting scaling factor value at the segment start.
     * @param endAmount The ending scaling factor value at the segment end.
     * @param startBlock The block number where this segment begins.
     * @param currentBlock The current block number within the segment.
     * @param endBlock The block number where this segment ends.
     * @param roundUp Whether to round up (true for exact-in) or down (false for exact-out).
     * @return amount The interpolated scaling factor for the current block.
     */
    function _locateCurrentAmount(
        uint256 startAmount,
        uint256 endAmount,
        uint256 startBlock,
        uint256 currentBlock,
        uint256 endBlock,
        bool roundUp
    ) private pure returns (uint256 amount) {
        // Only modify end amount if it doesn't already equal start amount.
        if (startAmount != endAmount) {
            // Declare variables to derive in the subsequent unchecked scope.
            uint256 duration;
            uint256 elapsed;
            uint256 remaining;

            // Skip underflow checks as startBlock <= _getBlockNumberish() < endBlock.
            unchecked {
                // Derive block duration and place it on the stack.
                duration = endBlock - startBlock;

                // Derive blocks elapsed since the start block & place on stack.
                elapsed = currentBlock - startBlock;

                // Derive blocks remaining until the end block & place on stack.
                remaining = duration - elapsed;
            }

            // Aggregate new amounts weighted by blocks with rounding factor.
            uint256 totalBeforeDivision = ((startAmount * remaining) + (endAmount * elapsed));

            // Use assembly to combine operations and skip divide-by-zero check.
            assembly {
                // Multiply by iszero(iszero(totalBeforeDivision)) to ensure
                // amount is set to zero if totalBeforeDivision is zero,
                // as intermediate overflow can occur if it is zero.
                amount := mul(
                    iszero(iszero(totalBeforeDivision)),
                    // Subtract 1 from the numerator and add 1 to the result
                    // if roundUp is true to get proper rounding direction.
                    // Division is performed with no zero check as duration
                    // cannot be zero as long as startBlock < endBlock.
                    add(div(sub(totalBeforeDivision, roundUp), duration), roundUp)
                )
            }

            // Return the current amount.
            return amount;
        }

        // Return the original amount as startAmount == endAmount.
        return endAmount;
    }

    /**
     * @notice Validates that two scaling factors scale in the same direction (both exact-in or both exact-out).
     * @dev Checks whether two values are on the same side of the neutral threshold (1e18), or if either equals 1e18.
     * Returns true if:
     * - Either value equals 1e18 (neutral scaling)
     * - Both values are > 1e18 (both exact-in mode)
     * - Both values are < 1e18 (both exact-out mode)
     * Returns false only if one value is strictly < 1e18 and the other strictly > 1e18, indicating incompatible
     * scaling directions. This validation ensures price curves don't switch between exact-in and exact-out modes.
     * @param a The first scaling factor to check.
     * @param b The second scaling factor to check.
     * @return result True if compatible scaling directions; false if incompatible (one exact-in, one exact-out).
     */
    function sharesScalingDirection(uint256 a, uint256 b) internal pure returns (bool result) {
        assembly {
            let threshold := 1000000000000000000

            result := or(
                or(eq(a, threshold), eq(b, threshold)), // either value is 1e18
                eq(gt(a, threshold), gt(b, threshold)) // both values are either greater or less than 1e18
            )
        }
    }
}

File 10 of 41 : EIP712Types.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

// Message signed by the sponsor that specifies the conditions under which their
// tokens can be claimed; the specified arbiter verifies that those conditions
// have been met and specifies a set of beneficiaries that will receive up to the
// specified amount of tokens.
struct Compact {
    address arbiter; // The account tasked with verifying and submitting the claim.
    address sponsor; // The account to source the tokens from.
    uint256 nonce; // A parameter to enforce replay protection, scoped to allocator.
    uint256 expires; // The time at which the claim expires.
    bytes12 lockTag; // A tag representing the allocator, reset period, and scope.
    address token; // The locked token, or address(0) for native tokens.
    uint256 amount; // The amount of ERC6909 tokens to commit from the lock.
        // Optional witness may follow.
}

// keccak256(bytes("Compact(address arbiter,address sponsor,uint256 nonce,uint256 expires,bytes12 lockTag,address token,uint256 amount)"))
bytes32 constant COMPACT_TYPEHASH = 0x73b631296de001508966ddfc334593ad8f850ccd3be4d2c58a9ed469844eebc7;

// abi.decode(bytes("Compact(address arbiter,address "), (bytes32))
bytes32 constant COMPACT_TYPESTRING_FRAGMENT_ONE = 0x436f6d70616374286164647265737320617262697465722c6164647265737320;

// abi.decode(bytes("sponsor,uint256 nonce,uint256 ex"), (bytes32))
bytes32 constant COMPACT_TYPESTRING_FRAGMENT_TWO = 0x73706f6e736f722c75696e74323536206e6f6e63652c75696e74323536206578;

// abi.decode(bytes("pires,bytes12 lockTag,address to"), (bytes32))
bytes32 constant COMPACT_TYPESTRING_FRAGMENT_THREE = 0x70697265732c62797465733132206c6f636b5461672c6164647265737320746f;

// abi.decode(bytes("ken,uint256 amount,Mandate manda"), (bytes32))
bytes32 constant COMPACT_TYPESTRING_FRAGMENT_FOUR = 0x6b656e2c75696e7432353620616d6f756e742c4d616e64617465206d616e6461;

// uint88(abi.decode(bytes("te)Mandate("), (bytes11)))
uint88 constant COMPACT_TYPESTRING_FRAGMENT_FIVE = 0x7465294d616e6461746528;

// A batch or multichain compact can contain commitments from multiple resource locks.
struct Lock {
    bytes12 lockTag; // A tag representing the allocator, reset period, and scope.
    address token; // The locked token, or address(0) for native tokens.
    uint256 amount; // The maximum committed amount of tokens.
}

// keccak256(bytes("Lock(bytes12 lockTag,address token,uint256 amount)"))
bytes32 constant LOCK_TYPEHASH = 0xfb7744571d97aa61eb9c2bc3c67b9b1ba047ac9e95afb2ef02bc5b3d9e64fbe5;

// Message signed by the sponsor that specifies the conditions under which a set of
// tokens, each sharing an allocator, can be claimed; the specified arbiter verifies
// that those conditions have been met and specifies a set of beneficiaries that will
// receive up to the specified amounts of each token.
struct BatchCompact {
    address arbiter; // The account tasked with verifying and submitting the claim.
    address sponsor; // The account to source the tokens from.
    uint256 nonce; // A parameter to enforce replay protection, scoped to allocator.
    uint256 expires; // The time at which the claim expires.
    Lock[] commitments; // The committed locks with lock tags, tokens, & amounts.
        // Optional witness may follow.
}

// keccak256(bytes("BatchCompact(address arbiter,address sponsor,uint256 nonce,uint256 expires,Lock[] commitments)Lock(bytes12 lockTag,address token,uint256 amount)"))
bytes32 constant BATCH_COMPACT_TYPEHASH = 0x179fcd593ea3b4b32623a455fb55eb007c5040f4c85774f2e3f18d98e87eb76b;

// abi.decode(bytes("BatchCompact(address arbiter,add"), (bytes32))
bytes32 constant BATCH_COMPACT_TYPESTRING_FRAGMENT_ONE =
    0x4261746368436f6d70616374286164647265737320617262697465722c616464;

// abi.decode(bytes("ress sponsor,uint256 nonce,uint2"), (bytes32))
bytes32 constant BATCH_COMPACT_TYPESTRING_FRAGMENT_TWO =
    0x726573732073706f6e736f722c75696e74323536206e6f6e63652c75696e7432;

// abi.decode(bytes("56 expires,Lock[] commitments,Ma"), (bytes32))
bytes32 constant BATCH_COMPACT_TYPESTRING_FRAGMENT_THREE =
    0x353620657870697265732c4c6f636b5b5d20636f6d6d69746d656e74732c4d61;

// abi.decode(bytes("ndate mandate)Lock(bytes12 lockT"), (bytes32))
bytes32 constant BATCH_COMPACT_TYPESTRING_FRAGMENT_FOUR =
    0x6e64617465206d616e64617465294c6f636b2862797465733132206c6f636b54;

// abi.decode(bytes("ag,address token,uint256 amount)"), (bytes32))
bytes32 constant BATCH_COMPACT_TYPESTRING_FRAGMENT_FIVE =
    0x61672c6164647265737320746f6b656e2c75696e7432353620616d6f756e7429;

// uint64(abi.decode(bytes("Mandate("), (bytes8)))
uint64 constant BATCH_COMPACT_TYPESTRING_FRAGMENT_SIX = 0x4d616e6461746528;

// A multichain compact can commit tokens from resource locks on multiple chains, each
// designated by their chainId. Any committed tokens on an exogenous domain (e.g. all
// but the first element) must designate the Multichain scope. Elements may designate
// unique arbiters for the chain in question. Note that the witness data is distinct
// for each element, but all elements must share the same EIP-712 witness typestring.
struct Element {
    address arbiter; // The account tasked with verifying and submitting the claim.
    uint256 chainId; // The chainId where the tokens are located.
    Lock[] commitments; // The committed locks with lock tags, tokens, & amounts.
        // Mandate (witness) must follow.
}

// Message signed by the sponsor that specifies the conditions under which a set of
// tokens across a number of different chains can be claimed; the specified arbiter on
// each chain verifies that those conditions have been met and specifies a set of
// beneficiaries that will receive up to the specified amounts of each token.
struct MultichainCompact {
    address sponsor; // The account to source the tokens from.
    uint256 nonce; // A parameter to enforce replay protection, scoped to allocator.
    uint256 expires; // The time at which the claim expires.
    Element[] elements; // Arbiter, chainId, ids & amounts, and mandate for each chain.
}

// keccak256(bytes("MultichainCompact(address sponsor,uint256 nonce,uint256 expires,Element[] elements)Element(address arbiter,uint256 chainId,Lock[] commitments)Lock(bytes12 lockTag,address token,uint256 amount)"))
bytes32 constant MULTICHAIN_COMPACT_TYPEHASH = 0x172d857ea70e48d30dcad00bb0fc789a34f09c5545da1245400da01d4ef6c8a2;

// abi.decode(bytes("MultichainCompact(address sponso"), (bytes32))
bytes32 constant MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_ONE =
    0x4d756c7469636861696e436f6d7061637428616464726573732073706f6e736f;

// abi.decode(bytes("r,uint256 nonce,uint256 expires,"), (bytes32))
bytes32 constant MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_TWO =
    0x722c75696e74323536206e6f6e63652c75696e7432353620657870697265732c;

// abi.decode(bytes("Element[] elements)Element(addre"), (bytes32))
bytes32 constant MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_THREE =
    0x456c656d656e745b5d20656c656d656e747329456c656d656e74286164647265;

// abi.decode(bytes("ss arbiter,uint256 chainId,Lock["), (bytes32))
bytes32 constant MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_FOUR =
    0x737320617262697465722c75696e7432353620636861696e49642c4c6f636b5b;

// abi.decode(bytes("] commitments,Mandate mandate)Lo"), (bytes32))
bytes32 constant MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_FIVE =
    0x5d20636f6d6d69746d656e74732c4d616e64617465206d616e64617465294c6f;

// abi.decode(bytes("ck(bytes12 lockTag,address token"), (bytes32))
bytes32 constant MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_SIX =
    0x636b2862797465733132206c6f636b5461672c6164647265737320746f6b656e;

// uint200(abi.decode(bytes(",uint256 amount)Mandate("), (bytes24))
uint192 constant MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_SEVEN = 0x2c75696e7432353620616d6f756e74294d616e6461746528;

// keccak256(bytes("Element(address arbiter,uint256 chainId,Lock[] commitments)Lock(bytes12 lockTag,address token,uint256 amount)"))
bytes32 constant ELEMENT_TYPEHASH = 0xc3e0b49b35866f940704f2fb568b9d5dae17a245971e2c095778b60ea177f03b;

/// @dev `keccak256(bytes("CompactDeposit(bytes12 lockTag,address recipient)"))`.
bytes32 constant PERMIT2_DEPOSIT_WITNESS_FRAGMENT_HASH =
    0xaced9f7c53bfda31d043cbef88f9ee23b8171ec904889af3d5d0b9b81914a404;

/// @dev `keccak256(bytes("Activation(address activator,uint256 id,Compact compact)Compact(address arbiter,address sponsor,uint256 nonce,uint256 expires,bytes12 lockTag,address token,uint256 amount)"))`.
bytes32 constant COMPACT_ACTIVATION_TYPEHASH = 0x8b05b54b25c4a22095273abeb15e89077542cdca8be672282102c3473780942c;

/// @dev `keccak256(bytes("Activation(address activator,uint256 id,BatchCompact compact)BatchCompact(address arbiter,address sponsor,uint256 nonce,uint256 expires,Lock[] commitments)Lock(bytes12 lockTag,address token,uint256 amount)"))`.
bytes32 constant BATCH_COMPACT_ACTIVATION_TYPEHASH = 0x5a6488a03f679efdf6390ea1cada208092f98514652ffa4036265fd48bcdbf4f;

/// @dev `keccak256(bytes("BatchActivation(address activator,uint256[] ids,Compact compact)Compact(address arbiter,address sponsor,uint256 nonce,uint256 expires,bytes12 lockTag,address token,uint256 amount)"))`.
bytes32 constant COMPACT_BATCH_ACTIVATION_TYPEHASH = 0x25686dcdaf36339365d8aad4b420a3460867a181238971ffae587b16c6d9660f;

/// @dev `keccak256(bytes("BatchActivation(address activator,uint256[] ids,BatchCompact compact)BatchCompact(address arbiter,address sponsor,uint256 nonce,uint256 expires,Lock[] commitments)Lock(bytes12 lockTag,address token,uint256 amount)"))`.
bytes32 constant BATCH_COMPACT_BATCH_ACTIVATION_TYPEHASH =
    0xa794ed1a28cdf297ac45a3eee4643e35d29b295a389368da5f6baa420872c9b7;

// abi.decode(bytes("Activation witness)Activation(ad"), (bytes32))
bytes32 constant PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_ONE =
    0x41637469766174696f6e207769746e6573732941637469766174696f6e286164;

// uint216(abi.decode(bytes("dress activator,uint256 id,"), (bytes27)))
uint216 constant PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_TWO =
    0x647265737320616374697661746f722c75696e743235362069642c;

// abi.decode(bytes("BatchActivation witness)BatchAct"), (bytes32))
bytes32 constant PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_ONE =
    0x426174636841637469766174696f6e207769746e657373294261746368416374;

// abi.decode(bytes("ivation(address activator,uint25"), (bytes32))
bytes32 constant PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_TWO =
    0x69766174696f6e286164647265737320616374697661746f722c75696e743235;

// uint64(abi.decode(bytes("6[] ids,"), (bytes8)))
uint64 constant PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_THREE = 0x365b5d206964732c;

// abi.decode(bytes("Compact compact)Compact(address "), (bytes32))
bytes32 constant PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_ONE =
    0x436f6d7061637420636f6d7061637429436f6d70616374286164647265737320;

// abi.decode(bytes("arbiter,address sponsor,uint256 "), (bytes32))
bytes32 constant PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_TWO =
    0x617262697465722c616464726573732073706f6e736f722c75696e7432353620;

// abi.decode(bytes("nonce,uint256 expires,bytes12 lo"), (bytes32))
bytes32 constant PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_THREE =
    0x6e6f6e63652c75696e7432353620657870697265732c62797465733132206c6f;

// abi.decode(bytes("ckTag,address token,uint256 amou"), (bytes32))
bytes32 constant PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_FOUR =
    0x636b5461672c6164647265737320746f6b656e2c75696e7432353620616d6f75;

// uint216(abi.decode(bytes("nt,Mandate mandate)Mandate("), (bytes27)))
uint216 constant PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_FIVE =
    0x6e742c4d616e64617465206d616e64617465294d616e6461746528;

// abi.decode(bytes("BatchCompact compact)BatchCompac"), (bytes32))
bytes32 constant PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_FRAGMENT_ONE =
    0x4261746368436f6d7061637420636f6d70616374294261746368436f6d706163;

// abi.decode(bytes("t(address arbiter,address sponso"), (bytes32))
bytes32 constant PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_FRAGMENT_TWO =
    0x74286164647265737320617262697465722c616464726573732073706f6e736f;

// abi.decode(bytes("r,uint256 nonce,uint256 expires,"), (bytes32))
bytes32 constant PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_FRAGMENT_THREE =
    0x722c75696e74323536206e6f6e63652c75696e7432353620657870697265732c;

// uint144(abi.decode(bytes("Lock[] commitments"), (bytes18)))
uint144 constant PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_FRAGMENT_FOUR = 0x4c6f636b5b5d20636f6d6d69746d656e7473;

// uint128(abi.decode(bytes(",Mandate mandate"), (bytes16)))
uint128 constant PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_MANDATE_FRAGMENT_ONE = 0x2c4d616e64617465206d616e64617465;

// abi.decode(bytes(")Lock(bytes12 lockTag,address to"), (bytes32))
bytes32 constant PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_FRAGMENT_FIVE =
    0x294c6f636b2862797465733132206c6f636b5461672c6164647265737320746f;

// uint152(abi.decode(bytes("ken,uint256 amount)"), (bytes19)))
uint152 constant PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_FRAGMENT_SIX = 0x6b656e2c75696e7432353620616d6f756e7429;

// uint64(abi.decode(bytes("Mandate("), (bytes8)))
uint64 constant PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_MANDATE_FRAGMENT_TWO = 0x4d616e6461746528;

// abi.decode(bytes(")TokenPermissions(address token,"), (bytes32))
bytes32 constant TOKEN_PERMISSIONS_TYPESTRING_FRAGMENT_ONE =
    0x29546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c;

// uint120(abi.decode(bytes("uint256 amount)"), (bytes15)))
uint120 constant TOKEN_PERMISSIONS_TYPESTRING_FRAGMENT_TWO = 0x75696e7432353620616d6f756e7429;

// abi.decode(bytes("CompactDeposit witness)CompactDe"), (bytes32))
uint256 constant COMPACT_DEPOSIT_TYPESTRING_FRAGMENT_ONE =
    0x436f6d706163744465706f736974207769746e65737329436f6d706163744465;

// abi.decode(bytes("posit(bytes12 lockTag,address re"), (bytes32))
uint256 constant COMPACT_DEPOSIT_TYPESTRING_FRAGMENT_TWO =
    0x706f7369742862797465733132206c6f636b5461672c61646472657373207265;

// abi.decode(bytes("cipient)TokenPermissions(address"), (bytes32))
uint256 constant COMPACT_DEPOSIT_TYPESTRING_FRAGMENT_THREE =
    0x63697069656e7429546f6b656e5065726d697373696f6e732861646472657373;

// uint176(abi.decode(bytes(" token,uint256 amount)"), (bytes22)))
uint176 constant COMPACT_DEPOSIT_TYPESTRING_FRAGMENT_FOUR = 0x20746f6b656e2c75696e7432353620616d6f756e7429;

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

import { Claim } from "../types/Claims.sol";

import { BatchClaim } from "../types/BatchClaims.sol";

import { MultichainClaim, ExogenousMultichainClaim } from "../types/MultichainClaims.sol";

import { BatchMultichainClaim, ExogenousBatchMultichainClaim } from "../types/BatchMultichainClaims.sol";

/**
 * @title The Compact — Claims Interface
 * @custom:version 1
 * @author 0age (0age.eth)
 * @custom:coauthor mgretzke (mgretzke.eth)
 * @custom:coauthor ccashwell (ccashwell.eth)
 * @custom:coauthor reednaa (reednaa.eth)
 * @custom:coauthor zeroknots (zeroknots.eth)
 * @custom:security-contact [email protected]
 * @notice Claim endpoints can only be called by the arbiter indicated on the associated
 * compact, and are used to settle the compact in question. There are six endpoints in
 * total, based on the following factors:
 *  - whether or not to utilize a "batch" of resource locks on a specific chain: When the
 *    sponsor is utilizing multiple resource locks on a specific chain, they will sign or
 *    register a `BatchCompact` EIP-712 payload. (Single-chain claims sign or register a
 *    `Compact` EIP-712 payload).
 *  - whether or not to include resource locks on a single chain or multiple chains; in
 *    the event of a multichain compact, there are _two_ additional endpoints per option:
 *    one for claims against the first referenced chain where the domain matches the one
 *    signed for or registered against (the "notarized" chain), and one for claims against
 *    other chains where the resource locks indicate a multichain scope (the "exogenous"
 *    chains). When the sponsor is utilizing multiple resource locks across multiple chains,
 *    they will sign a `MultichainCompact` EIP-712 payload. When processing claims against
 *    the notarized chain, an array of bytes32 values representing the hash of each
 *    exogenous chain "element" is provided (the "additional chains" array). When processing
 *    claims against an exogenous chain, the additional chains array begins with the element
 *    hash of the notarized chain and includes values for all exogenous chains excluding the
 *    one being claimed against, and a "chain index" value is supplied indicating the
 *    location in the list of elements of the current chain (a value of 0 means that it is
 *    the first exogenous chain) as well as a `notarizedChainId` representing the chainId
 *    for the domain that the multichain claim was signed against.
 */
interface ITheCompactClaims {
    /**
     * @notice Process a standard single-chain claim.
     * @param claimPayload The claim data containing signature, allocator data, and compact details.
     * @return claimHash   The hash of the processed claim.
     */
    function claim(Claim calldata claimPayload) external returns (bytes32 claimHash);

    /**
     * @notice Process a batch claim for multiple resource locks on a single chain.
     * @param claimPayload The batch claim data containing signature, allocator data, and compact details.
     * @return claimHash   The hash of the processed batch claim.
     */
    function batchClaim(BatchClaim calldata claimPayload) external returns (bytes32 claimHash);

    /**
     * @notice Process a multichain claim for the notarized chain (where domain matches the one signed for).
     * @param claimPayload The multichain claim data containing signature, allocator data, compact details, and chain elements.
     * @return claimHash   The hash of the processed multichain claim.
     */
    function multichainClaim(MultichainClaim calldata claimPayload) external returns (bytes32 claimHash);

    /**
     * @notice Process a multichain claim for an exogenous chain (not the notarized chain).
     * @param claimPayload The exogenous multichain claim data containing signature, allocator data, compact details, chain index, and notarized chain ID.
     * @return claimHash   The hash of the processed exogenous multichain claim.
     */
    function exogenousClaim(ExogenousMultichainClaim calldata claimPayload) external returns (bytes32 claimHash);

    /**
     * @notice Process a batch multichain claim for multiple resource locks on the notarized chain.
     * @param claimPayload The batch multichain claim data containing signature, allocator data, compact details, and chain elements.
     * @return claimHash   The hash of the processed batch multichain claim.
     */
    function batchMultichainClaim(BatchMultichainClaim calldata claimPayload) external returns (bytes32 claimHash);

    /**
     * @notice Process a batch multichain claim for multiple resource locks on an exogenous chain.
     * @param claimPayload The exogenous batch multichain claim data containing signature, allocator data, compact details, chain index, and notarized chain ID.
     * @return claimHash   The hash of the processed exogenous batch multichain claim.
     */
    function exogenousBatchClaim(ExogenousBatchMultichainClaim calldata claimPayload)
        external
        returns (bytes32 claimHash);
}

File 12 of 41 : ITheCompact.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { ForcedWithdrawalStatus } from "../types/ForcedWithdrawalStatus.sol";
import { EmissaryStatus } from "../types/EmissaryStatus.sol";
import { ResetPeriod } from "../types/ResetPeriod.sol";
import { Scope } from "../types/Scope.sol";
import { CompactCategory } from "../types/CompactCategory.sol";
import { ISignatureTransfer } from "permit2/src/interfaces/ISignatureTransfer.sol";
import { AllocatedTransfer } from "../types/Claims.sol";
import { DepositDetails } from "../types/DepositDetails.sol";
import { AllocatedBatchTransfer } from "../types/BatchClaims.sol";

/**
 * @title The Compact — Core Interface
 * @custom:version 1
 * @author 0age (0age.eth)
 * @custom:coauthor mgretzke (mgretzke.eth)
 * @custom:coauthor ccashwell (ccashwell.eth)
 * @custom:coauthor reednaa (reednaa.eth)
 * @custom:coauthor zeroknots (zeroknots.eth)
 * @custom:security-contact [email protected]
 * @notice The Compact is an ownerless ERC6909 contract that facilitates the voluntary
 * formation and mediation of reusable "resource locks." This interface contract specifies
 * external functions for making deposits, for performing allocated transfers and
 * withdrawals, for initiating and performing forced withdrawals, and for registering
 * compact claim hashes and typehashes directly. It also contains methods for registering
 * allocators and for enabling allocators to consume nonces directly. Finally, it specifies
 * a number of view functions, events and errors.
 */
interface ITheCompact {
    /**
     * @notice Event indicating that a claim has been processed for a given compact.
     * @param sponsor   The account sponsoring the claimed compact.
     * @param allocator The account mediating the resource locks utilized by the claim.
     * @param arbiter   The account verifying and initiating the settlement of the claim.
     * @param claimHash A bytes32 hash derived from the details of the claimed compact.
     * @param nonce     The nonce (scoped to the allocator) on the claimed compact.
     */
    event Claim(
        address indexed sponsor, address indexed allocator, address indexed arbiter, bytes32 claimHash, uint256 nonce
    );

    /**
     * @notice Event indicating that a nonce has been consumed directly.
     * @param allocator The account mediating the nonces.
     * @param nonce     The nonce (scoped to the allocator) in question.
     */
    event NonceConsumedDirectly(address indexed allocator, uint256 nonce);

    /**
     * @notice Event indicating a change in forced withdrawal status.
     * @param account        The account for which the withdrawal status has changed.
     * @param id             The ERC6909 token identifier of the associated resource lock.
     * @param activating     Whether the forced withdrawal is being activated or has been deactivated.
     * @param withdrawableAt The timestamp when tokens become withdrawable if it is being activated.
     */
    event ForcedWithdrawalStatusUpdated(
        address indexed account, uint256 indexed id, bool activating, uint256 withdrawableAt
    );

    /**
     * @notice Event indicating that a compact has been registered directly.
     * @param sponsor   The address registering the compact in question.
     * @param claimHash A bytes32 hash derived from the details of the compact.
     * @param typehash  The EIP-712 typehash associated with the registered compact.
     */
    event CompactRegistered(address indexed sponsor, bytes32 claimHash, bytes32 typehash);

    /**
     * @notice Event indicating that an emissary has been assigned for a given sponsor and lock tag.
     * @param sponsor  The address for which the emissary has been assigned.
     * @param lockTag  The lock tag for which the emissary has been assigned.
     * @param emissary The account of the emissary that has been assigned.
     */
    event EmissaryAssigned(address indexed sponsor, bytes12 indexed lockTag, address indexed emissary);

    /**
     * @notice Event indicating that a new emissary assignment has been scheduled for a given sponsor
     * and lock tag. Note that this is only required when a previous emissary has already been assigned
     * for the given combination of sponsor and lock tag.
     * @param sponsor      The address for which the emissary assignment has been scheduled.
     * @param lockTag      The lock tag for which the emissary assignment has been scheduled.
     * @param assignableAt The block timestamp at which a new emissary may be assigned.
     */
    event EmissaryAssignmentScheduled(address indexed sponsor, bytes12 indexed lockTag, uint256 assignableAt);

    /**
     * @notice Event indicating an allocator has been registered.
     * @param allocatorId The unique identifier assigned to the allocator.
     * @param allocator   The address of the registered allocator.
     */
    event AllocatorRegistered(uint96 allocatorId, address allocator);

    /**
     * @notice External payable function for depositing native tokens into a resource lock with
     * custom reset period and scope parameters. The ERC6909 token amount received by the recipient
     * will match the amount of native tokens sent with the transaction. Note that supplying the
     * null address for the recipient will result in the caller being applied as the recipient.
     * @param lockTag   The lock tag containing allocator ID, reset period, and scope.
     * @param recipient The address that will receive the corresponding ERC6909 tokens.
     * @return id       The ERC6909 token identifier of the associated resource lock.
     */
    function depositNative(bytes12 lockTag, address recipient) external payable returns (uint256 id);

    /**
     * @notice External function for depositing ERC20 tokens into a resource lock with custom reset
     * period and scope parameters. The caller must directly approve The Compact to transfer a
     * sufficient amount of the ERC20 token on its behalf. The ERC6909 token amount received by
     * the recipient is derived from the difference between the starting and ending balance held
     * in the resource lock, which may differ from the amount transferred depending on the
     * implementation details of the respective token.  Note that supplying the null address for
     * the recipient will result in the caller being applied as the recipient.
     * @param token     The address of the ERC20 token to deposit.
     * @param lockTag   The lock tag containing allocator ID, reset period, and scope.
     * @param amount    The amount of tokens to deposit.
     * @param recipient The address that will receive the corresponding ERC6909 tokens.
     * @return id       The ERC6909 token identifier of the associated resource lock.
     */
    function depositERC20(address token, bytes12 lockTag, uint256 amount, address recipient)
        external
        returns (uint256 id);

    /**
     * @notice External payable function for depositing multiple tokens in a single transaction.
     * The first entry in idsAndAmounts can optionally represent native tokens by providing the
     * null address and an amount matching msg.value. For ERC20 tokens, the caller must directly
     * approve The Compact to transfer sufficient amounts on its behalf. The ERC6909 token amounts
     * received by the recipient are derived from the differences between starting and ending
     * balances held in the resource locks, which may differ from the amounts transferred depending
     * on the implementation details of the respective tokens.  Note that supplying the null
     * address for the recipient will result in the caller being applied as the recipient.
     * @param idsAndAmounts Array of [id, amount] pairs indicating resource locks & amounts to deposit.
     * @param recipient     The address that will receive the corresponding ERC6909 tokens.
     * @return              Whether the batch deposit was successfully completed.
     */
    function batchDeposit(uint256[2][] calldata idsAndAmounts, address recipient) external payable returns (bool);

    /**
     * @notice External function for depositing ERC20 tokens using Permit2 authorization. The
     * depositor must approve Permit2 to transfer the tokens on its behalf unless the token in
     * question automatically grants approval to Permit2. The ERC6909 token amount received by the
     * recipient is derived from the difference between the starting and ending balance held
     * in the resource lock, which may differ from the amount transferred depending on the
     * implementation details of the respective token. The Permit2 authorization signed by the
     * depositor must contain a CompactDeposit witness containing the allocator, the reset period,
     * the scope, and the intended recipient of the deposit.
     * @param permit    The permit data signed by the depositor.
     * @param depositor The account signing the permit2 authorization and depositing the tokens.
     * @param lockTag   The lock tag containing allocator ID, reset period, and scope.
     * @param recipient The address that will receive the corresponding the ERC6909 tokens.
     * @param signature The Permit2 signature from the depositor authorizing the deposit.
     * @return id       The ERC6909 token identifier of the associated resource lock.
     */
    function depositERC20ViaPermit2(
        ISignatureTransfer.PermitTransferFrom calldata permit,
        address depositor,
        bytes12 lockTag,
        address recipient,
        bytes calldata signature
    ) external returns (uint256 id);

    /**
     * @notice External payable function for depositing multiple tokens using Permit2
     * authorization in a single transaction. The first token id can optionally represent native
     * tokens by providing the null address and an amount matching msg.value. The depositor must
     * approve Permit2 to transfer the tokens on its behalf unless the tokens automatically
     * grant approval to Permit2. The ERC6909 token amounts received by the recipient are derived
     * from the differences between starting and ending balances held in the resource locks,
     * which may differ from the amounts transferred depending on the implementation details of
     * the respective tokens. The Permit2 authorization signed by the depositor must contain a
     * CompactDeposit witness containing the allocator, the reset period, the scope, and the
     * intended recipient of the deposits.
     * @param depositor The account signing the permit2 authorization and depositing the tokens.
     * @param permitted The permit data signed by the depositor.
     * @param details   The details of the deposit.
     * @param recipient The address that will receive the corresponding ERC6909 tokens.
     * @param signature The Permit2 signature from the depositor authorizing the deposits.
     * @return ids      Array of ERC6909 token identifiers for the associated resource locks.
     */
    function batchDepositViaPermit2(
        address depositor,
        ISignatureTransfer.TokenPermissions[] calldata permitted,
        DepositDetails calldata details,
        address recipient,
        bytes calldata signature
    ) external payable returns (uint256[] memory ids);

    /**
     * @notice Transfers or withdraws ERC6909 tokens to multiple recipients with allocator approval.
     * @param transfer A Transfer struct containing the following:
     *  -  allocatorData Authorization signature from the allocator.
     *  -  nonce         Parameter enforcing replay protection, scoped to the allocator.
     *  -  expires       Timestamp after which the transfer cannot be executed.
     *  -  id            The ERC6909 token identifier of the resource lock.
     *  -  recipients    A Component array, each containing:
     *     -  claimant   The account that will receive tokens.
     *     -  amount     The amount of tokens the claimant will receive.
     * @return           Boolean indicating whether the transfer or withdrawal was successful.
     */
    function allocatedTransfer(AllocatedTransfer calldata transfer) external returns (bool);

    /**
     * @notice Transfers or withdraws ERC6909 tokens from multiple resource locks to multiple
     *         recipients with allocator approval.
     * @param transfer A BatchTransfer struct containing the following:
     *  -  allocatorData  Authorization signature from the allocator.
     *  -  nonce          Parameter enforcing replay protection, scoped to the allocator.
     *  -  expires        Timestamp after which the transfer cannot be executed.
     *  -  transfers      Array of ComponentsById, each containing:
     *     -  id          The ERC6909 token identifier of the resource lock.
     *     -  portions    A Component array, each containing:
     *        -  claimant The account that will receive tokens.
     *        -  amount   The amount of tokens the claimant will receive.
     * @return            Boolean indicating whether the transfer was successful.
     */
    function allocatedBatchTransfer(AllocatedBatchTransfer calldata transfer) external returns (bool);

    /**
     * @notice External function to register a claim hash and its associated EIP-712 typehash.
     * The registered claim hash will remain valid until the allocator consumes the nonce.
     * @param claimHash A bytes32 hash derived from the details of the compact.
     * @param typehash  The EIP-712 typehash associated with the registered claim hash.
     * @return          Boolean indicating whether the claim hash was successfully registered.
     */
    function register(bytes32 claimHash, bytes32 typehash) external returns (bool);

    /**
     * @notice External function to register multiple claim hashes and their associated EIP-712
     * typehashes in a single call. Each registered claim hash will remain valid until the allocator
     * consumes the nonce.
     * @param claimHashesAndTypehashes Array of [claimHash, typehash] pairs for registration.
     * @return                         Boolean indicating whether all claim hashes were successfully registered.
     */
    function registerMultiple(bytes32[2][] calldata claimHashesAndTypehashes) external returns (bool);

    /**
     * @notice Register a claim on behalf of a sponsor with their signature.
     * @param typehash         The EIP-712 typehash associated with the registered compact.
     * @param arbiter          The account tasked with verifying and submitting the claim.
     * @param sponsor          The address of the sponsor for whom the claim is being registered.
     * @param nonce            A parameter to enforce replay protection, scoped to allocator.
     * @param expires          The time at which the claim expires.
     * @param lockTag          The lock tag containing allocator ID, reset period, and scope.
     * @param token            The address of the token associated with the claim.
     * @param amount           The amount of tokens associated with the claim.
     * @param witness          Hash of the witness data.
     * @param sponsorSignature The signature from the sponsor authorizing the registration.
     * @return claimHash       Hash for verifying that the expected compact was registered.
     */
    function registerFor(
        bytes32 typehash,
        address arbiter,
        address sponsor,
        uint256 nonce,
        uint256 expires,
        bytes12 lockTag,
        address token,
        uint256 amount,
        bytes32 witness,
        bytes calldata sponsorSignature
    ) external returns (bytes32 claimHash);

    /**
     * @notice Register a batch claim on behalf of a sponsor with their signature.
     * @param typehash          The EIP-712 typehash associated with the registered compact.
     * @param arbiter           The account tasked with verifying and submitting the claim.
     * @param sponsor           The address of the sponsor for whom the claim is being registered.
     * @param nonce             A parameter to enforce replay protection, scoped to allocator.
     * @param expires           The time at which the claim expires.
     * @param idsAndAmountsHash Hash of array of [id, amount] pairs per resource lock.
     * @param witness           Hash of the witness data.
     * @param sponsorSignature  The signature from the sponsor authorizing the registration.
     * @return claimHash        Hash for verifying that the expected compact was registered.
     */
    function registerBatchFor(
        bytes32 typehash,
        address arbiter,
        address sponsor,
        uint256 nonce,
        uint256 expires,
        bytes32 idsAndAmountsHash,
        bytes32 witness,
        bytes calldata sponsorSignature
    ) external returns (bytes32 claimHash);

    /**
     * @notice Register a multichain claim on behalf of a sponsor with their signature.
     * @param typehash         The EIP-712 typehash associated with the registered compact.
     * @param sponsor          The address of the sponsor for whom the claim is being registered.
     * @param nonce            A parameter to enforce replay protection, scoped to allocator.
     * @param expires          The time at which the claim expires.
     * @param elementsHash     Hash of elements (arbiter, chainId, idsAndAmounts, & mandate) per chain.
     * @param notarizedChainId Chain ID of the domain used to sign the multichain compact.
     * @param sponsorSignature The signature from the sponsor authorizing the registration.
     * @return claimHash       Hash for verifying that the expected compact was registered.
     */
    function registerMultichainFor(
        bytes32 typehash,
        address sponsor,
        uint256 nonce,
        uint256 expires,
        bytes32 elementsHash,
        uint256 notarizedChainId,
        bytes calldata sponsorSignature
    ) external returns (bytes32 claimHash);

    /**
     * @notice External payable function for depositing native tokens into a resource lock
     * and simultaneously registering a compact. The allocator, the claim hash, and the typehash
     * used for the claim hash are provided as additional arguments, and the default reset period
     * (ten minutes) and scope (multichain) will be used for the resource lock. The ERC6909 token
     * amount received by the caller will match the amount of native tokens sent with the transaction.
     * @param lockTag   The lock tag containing allocator ID, reset period, and scope.
     * @param claimHash A bytes32 hash derived from the details of the compact.
     * @param typehash  The EIP-712 typehash associated with the registered compact.
     * @return id       The ERC6909 token identifier of the associated resource lock.
     */
    function depositNativeAndRegister(bytes12 lockTag, bytes32 claimHash, bytes32 typehash)
        external
        payable
        returns (uint256 id);

    /**
     * @notice External payable function for depositing native tokens and simultaneously registering a
     * compact on behalf of someone else. The amount of the claim must be explicitly provided otherwise
     * a wrong claim hash may be derived.
     * @param recipient  The recipient of the ERC6909 token.
     * @param lockTag    The lock tag containing allocator ID, reset period, and scope.
     * @param arbiter    The account tasked with verifying and submitting the claim.
     * @param nonce      A parameter to enforce replay protection, scoped to allocator.
     * @param expires    The time at which the claim expires.
     * @param typehash   The EIP-712 typehash associated with the registered compact.
     * @param witness    Hash of the witness data.
     * @return id        The ERC6909 token identifier of the associated resource lock.
     * @return claimHash Hash for verifying that the expected compact was registered.
     */
    function depositNativeAndRegisterFor(
        address recipient,
        bytes12 lockTag,
        address arbiter,
        uint256 nonce,
        uint256 expires,
        bytes32 typehash,
        bytes32 witness
    ) external payable returns (uint256 id, bytes32 claimHash);

    /**
     * @notice External function for depositing ERC20 tokens and simultaneously registering a
     * compact. The default reset period (ten minutes) and scope (multichain) will be used. The
     * caller must directly approve The Compact to transfer a sufficient amount of the ERC20 token
     * on its behalf. The ERC6909 token amount received back by the caller is derived from the
     * difference between the starting and ending balance held in the resource lock, which may differ
     * from the amount transferred depending on the implementation details of the respective token.
     * @param token     The address of the ERC20 token to deposit.
     * @param lockTag   The lock tag containing allocator ID, reset period, and scope.
     * @param amount    The amount of tokens to deposit.
     * @param claimHash A bytes32 hash derived from the details of the compact.
     * @param typehash  The EIP-712 typehash associated with the registered compact.
     * @return id       The ERC6909 token identifier of the associated resource lock.
     */
    function depositERC20AndRegister(
        address token,
        bytes12 lockTag,
        uint256 amount,
        bytes32 claimHash,
        bytes32 typehash
    ) external returns (uint256 id);

    /**
     * @notice External function for depositing ERC20 tokens and simultaneously registering a
     * compact on behalf of someone else. The caller must directly approve The Compact to transfer
     * a sufficient amount of the ERC20 token on its behalf. The ERC6909 token amount received by
     * designated recipient the caller is derived from the difference between the starting and ending
     * balance held in the resource lock, which may differ from the amount transferred depending on
     * the implementation details of the respective token.
     * @dev The final ERC6909 token amounts will be substituted into the compact which will be
     * registered with the returned registeredAmount instead of the provided amount.
     * Ensure the claim is processed using either the registeredAmount or the ERC6909 transfer event.
     * This is especially important for fee-on-transfer tokens.
     * @param recipient         The recipient of the ERC6909 token.
     * @param token             The address of the ERC20 token to deposit.
     * @param lockTag           Lock tag containing allocator ID, reset period, & scope.
     * @param amount            The amount of tokens to deposit.
     * @param arbiter           The account tasked with verifying and submitting the claim.
     * @param nonce             A parameter to enforce replay protection, scoped to allocator.
     * @param expires           The time at which the claim expires.
     * @param typehash          The EIP-712 typehash associated with the registered compact.
     * @param witness           Hash of the witness data.
     * @return id               The ERC6909 token identifier of the associated resource lock.
     * @return claimHash        Hash for verifying that the expected compact was registered.
     * @return registeredAmount Final registered amount after potential transfer fees.
     */
    function depositERC20AndRegisterFor(
        address recipient,
        address token,
        bytes12 lockTag,
        uint256 amount,
        address arbiter,
        uint256 nonce,
        uint256 expires,
        bytes32 typehash,
        bytes32 witness
    ) external returns (uint256 id, bytes32 claimHash, uint256 registeredAmount);

    /**
     * @notice External payable function for depositing multiple tokens in a single transaction
     * and registering a set of claim hashes. The first entry in idsAndAmounts can optionally
     * represent native tokens by providing the null address and an amount matching msg.value. For
     * ERC20 tokens, the caller must directly approve The Compact to transfer sufficient amounts
     * on its behalf. The ERC6909 token amounts received by the recipient are derived from the
     * differences between starting and ending balances held in the resource locks, which may
     * differ from the amounts transferred depending on the implementation details of the
     * respective tokens. Note that resource lock ids must be supplied in alphanumeric order.
     * @param idsAndAmounts            Array of [id, amount] pairs indicating resource locks & amounts to deposit.
     * @param claimHashesAndTypehashes Array of [claimHash, typehash] pairs for registration.
     * @return                         Boolean indicating whether the batch deposit & claim hash registration was successful.
     */
    function batchDepositAndRegisterMultiple(
        uint256[2][] calldata idsAndAmounts,
        bytes32[2][] calldata claimHashesAndTypehashes
    ) external payable returns (bool);

    /**
     * @notice External function for depositing ERC20 tokens and simultaneously registering a
     * batch compact on behalf of someone else. The caller must directly approve The Compact
     * to transfer a sufficient amount of the ERC20 token on its behalf. The ERC6909 token amount
     * received by designated recipient the caller is derived from the difference between the
     * starting and ending balance held in the resource lock, which may differ from the amount
     * transferred depending on the implementation details of the respective token.
     * @dev The final ERC6909 token amounts will be substituted into the compact which will be
     * registered with the returned registeredAmounts instead of the provided idsAndAmounts.
     * Ensure the claim is processed using either the registeredAmounts or the ERC6909 transfer events.
     * This is especially important for fee-on-transfer tokens.
     * @param recipient          The recipient of the ERC6909 token.
     * @param idsAndAmounts      Array of [id, amount] pairs indicating resource locks & amounts to deposit.
     * @param arbiter            The account tasked with verifying and submitting the claim.
     * @param nonce              A parameter to enforce replay protection, scoped to allocator.
     * @param expires            The time at which the claim expires.
     * @param typehash           The EIP-712 typehash associated with the registered compact.
     * @param witness            Hash of the witness data.
     * @return claimHash         Hash for verifying that the expected compact was registered.
     * @return registeredAmounts Array containing the final minted amount of each id.
     */
    function batchDepositAndRegisterFor(
        address recipient,
        uint256[2][] calldata idsAndAmounts,
        address arbiter,
        uint256 nonce,
        uint256 expires,
        bytes32 typehash,
        bytes32 witness
    ) external payable returns (bytes32 claimHash, uint256[] memory registeredAmounts);

    /**
     * @notice External function for depositing ERC20 tokens using Permit2 authorization and
     * registering a compact. The depositor must approve Permit2 to transfer the tokens on its
     * behalf unless the token in question automatically grants approval to Permit2. The ERC6909
     * token amount received by the depositor is derived from the difference between the starting
     * and ending balance held in the resource lock, which may differ from the amount transferred
     * depending on the implementation details of the respective token. The Permit2 authorization
     * signed by the depositor must contain an Activation witness containing the id of the resource
     * lock and an associated Compact, BatchCompact, or MultichainCompact payload matching the
     * specified compact category.
     * @param permit          The permit data signed by the depositor.
     * @param depositor       The account signing the permit2 authorization and depositing the tokens.
     * @param lockTag         The lock tag containing allocator ID, reset period, and scope.
     * @param claimHash       A bytes32 hash derived from the details of the compact.
     * @param compactCategory The category of the compact being registered (Compact, BatchCompact, or MultichainCompact).
     * @param witness         Additional data used in generating the claim hash.
     * @param signature       The Permit2 signature from the depositor authorizing the deposit.
     * @return id             The ERC6909 token identifier of the associated resource lock.
     */
    function depositERC20AndRegisterViaPermit2(
        ISignatureTransfer.PermitTransferFrom calldata permit,
        address depositor,
        bytes12 lockTag,
        bytes32 claimHash,
        CompactCategory compactCategory,
        string calldata witness,
        bytes calldata signature
    ) external returns (uint256 id);

    /**
     * @notice External payable function for depositing multiple tokens using Permit2
     * authorization and registering a compact in a single transaction. The first token id can
     * optionally represent native tokens by providing the null address and an amount matching
     * msg.value. The depositor must approve Permit2 to transfer the tokens on its behalf unless
     * the tokens automatically grant approval to Permit2. The ERC6909 token amounts received by
     * the depositor are derived from the differences between starting and ending balances held
     * in the resource locks, which may differ from the amounts transferred depending on the
     * implementation details of the respective tokens. The Permit2 authorization signed by the
     * depositor must contain a BatchActivation witness containing the ids of the resource locks
     * and an associated Compact, BatchCompact, or MultichainCompact payload matching the
     * specified compact category.
     * @param depositor       The account signing the permit2 authorization and depositing the tokens.
     * @param permitted       Array of token permissions specifying the deposited tokens and amounts.
     * @param details         The details of the deposit.
     * @param claimHash       A bytes32 hash derived from the details of the compact.
     * @param compactCategory The category of the compact being registered (Compact, BatchCompact, or MultichainCompact).
     * @param witness         Additional data used in generating the claim hash.
     * @param signature       The Permit2 signature from the depositor authorizing the deposits.
     * @return ids            Array of ERC6909 token identifiers for the associated resource locks.
     */
    function batchDepositAndRegisterViaPermit2(
        address depositor,
        ISignatureTransfer.TokenPermissions[] calldata permitted,
        DepositDetails calldata details,
        bytes32 claimHash,
        CompactCategory compactCategory,
        string calldata witness,
        bytes calldata signature
    ) external payable returns (uint256[] memory ids);

    /**
     * @notice External function to initiate a forced withdrawal for a resource lock. Once
     * enabled, forced withdrawals can be executed after the reset period has elapsed. The
     * withdrawableAt timestamp returned will be the current timestamp plus the reset period
     * associated with the resource lock.
     * @param id              The ERC6909 token identifier for the resource lock.
     * @return withdrawableAt The timestamp at which tokens become withdrawable.
     */
    function enableForcedWithdrawal(uint256 id) external returns (uint256 withdrawableAt);

    /**
     * @notice External function to disable a previously enabled forced withdrawal for a
     * resource lock.
     * @param id The ERC6909 token identifier for the resource lock.
     * @return   Boolean indicating whether the forced withdrawal was successfully disabled.
     */
    function disableForcedWithdrawal(uint256 id) external returns (bool);

    /**
     * @notice External function to execute a forced withdrawal from a resource lock after the
     * reset period has elapsed. The tokens will be withdrawn to the specified recipient in the
     * amount requested. The ERC6909 token balance of the caller will be reduced by the
     * difference in the balance held by the resource lock before and after the withdrawal,
     * which may differ from the provided amount depending on the underlying token in question.
     * @param id        The ERC6909 token identifier for the resource lock.
     * @param recipient The account that will receive the withdrawn tokens.
     * @param amount    The amount of tokens to withdraw.
     * @return          Boolean indicating whether the forced withdrawal was successfully executed.
     */
    function forcedWithdrawal(uint256 id, address recipient, uint256 amount) external returns (bool);

    /**
     * @notice Assigns an emissary for the caller that has authority to authorize claims where that
     * caller is the sponsor. The emissary will utilize a reset period dictated by the reset period
     * on the provided lock tag that blocks reassignment of the emissary for the duration of that
     * reset period. The reset period ensures that once an emissary is assigned, another assignment
     * cannot be made until the reset period has elapsed.
     * @param lockTag  The lockTag the emissary will be assigned for.
     * @param emissary The emissary to assign for the given caller and lock tag.
     * @return         Boolean indicating whether the assignment was successful.
     */
    function assignEmissary(bytes12 lockTag, address emissary) external returns (bool);

    /**
     * @notice Schedules a future emissary assignment for a specific lock tag. The reset period on
     * the lock tag determines how long reassignment will be blocked after this assignment. This
     * allows for a delay before the next assignment can be made. Note that the reset period of the
     * current emissary (if set) will dictate when the next assignment will be allowed.
     * @param lockTag                        The lockTag the emissary assignment is scheduled for.
     * @return emissaryAssignmentAvailableAt The timestamp when the next assignment will be allowed.
     */
    function scheduleEmissaryAssignment(bytes12 lockTag) external returns (uint256 emissaryAssignmentAvailableAt);

    /**
     * @notice External function for consuming allocator nonces. Only callable by a registered
     * allocator. Once consumed, any compact payloads that utilize those nonces cannot be claimed.
     * @param nonces Array of nonces to be consumed.
     * @return       Boolean indicating whether all nonces were successfully consumed.
     */
    function consume(uint256[] calldata nonces) external returns (bool);

    /**
     * @notice External function for registering an allocator. Can be called by anyone if one
     * of three conditions is met: the caller is the allocator address being registered, the
     * allocator address contains code, or a proof is supplied representing valid create2
     * deployment parameters that resolve to the supplied allocator address.
     * @param allocator    The address to register as an allocator.
     * @param proof        An 85-byte value containing create2 address derivation parameters (0xff ++ factory ++ salt ++ initcode hash).
     * @return allocatorId A unique identifier assigned to the registered allocator.
     */
    function __registerAllocator(address allocator, bytes calldata proof) external returns (uint96 allocatorId);

    /**
     * @notice External function to benchmark withdrawal costs to determine the required stipend
     * on the fallback for failing withdrawals when processing claims. The salt is used to derive
     * a cold account to benchmark the native token withdrawal. Note that exactly 2 wei must be
     * provided when calling this function, and that the provided wei will be irrecoverable.
     * @param salt A bytes32 value used to derive a cold account for benchmarking.
     */
    function __benchmark(bytes32 salt) external payable;

    /**
     * @notice External view function for retrieving the details of a resource lock. Returns the
     * underlying token, the mediating allocator, the reset period, and the scope.
     * @param id           The ERC6909 token identifier of the resource lock.
     * @return token       The address of the underlying token (or address(0) for native tokens).
     * @return allocator   The account of the allocator mediating the resource lock.
     * @return resetPeriod The duration after which the resource lock can be reset once a forced withdrawal is initiated.
     * @return scope       The scope of the resource lock (multichain or single chain).
     * @return lockTag     The lock tag containing the allocator ID, the reset period, and the scope.
     */
    function getLockDetails(uint256 id)
        external
        view
        returns (address token, address allocator, ResetPeriod resetPeriod, Scope scope, bytes12 lockTag);

    /**
     * @notice External view function for checking the registration status of a compact. Returns
     * both whether the claim hash is currently active and when it was registered (if relevant).
     * Note that an "active" compact may in fact not be claimable, (e.g. it has expired, the
     * nonce has been consumed, etc).
     * @param sponsor   The account that registered the compact.
     * @param claimHash A bytes32 hash derived from the details of the compact.
     * @param typehash  The EIP-712 typehash associated with the registered claim hash.
     * @return isActive Boolean indicating whether the compact registration is currently active.
     */
    function isRegistered(address sponsor, bytes32 claimHash, bytes32 typehash) external view returns (bool isActive);

    /**
     * @notice External view function for checking the forced withdrawal status of a resource
     * lock for a given account. Returns both the current status (disabled, pending, or enabled)
     * and the timestamp at which forced withdrawals will be enabled (if status is pending) or
     * became enabled (if status is enabled).
     * @param account                      The account to get the forced withdrawal status for.
     * @param id                           The ERC6909 token identifier of the resource lock.
     * @return status                      The current ForcedWithdrawalStatus (disabled, pending, or enabled).
     * @return forcedWithdrawalAvailableAt The timestamp at which tokens become withdrawable if status is pending.
     */
    function getForcedWithdrawalStatus(address account, uint256 id)
        external
        view
        returns (ForcedWithdrawalStatus status, uint256 forcedWithdrawalAvailableAt);

    /**
     * @notice Gets the current emissary status for an allocator. Returns the current status,
     * the timestamp when reassignment will be allowed again (based on reset period), and
     * the currently assigned emissary (if any).
     * @param sponsor                        The address of the sponsor to check.
     * @param lockTag                        The lockTag to check.
     * @return status                        The current emissary assignment status.
     * @return emissaryAssignmentAvailableAt The timestamp when reassignment will be allowed.
     * @return currentEmissary               The currently assigned emissary address (or zero address if none).
     */
    function getEmissaryStatus(address sponsor, bytes12 lockTag)
        external
        view
        returns (EmissaryStatus status, uint256 emissaryAssignmentAvailableAt, address currentEmissary);

    /**
     * @notice External view function for checking whether a specific nonce has been consumed by
     * an allocator. Once consumed, a nonce cannot be reused for claims mediated by that allocator.
     * @param nonce     The nonce to check.
     * @param allocator The account of the allocator.
     * @return consumed Boolean indicating whether the nonce has been consumed.
     */
    function hasConsumedAllocatorNonce(uint256 nonce, address allocator) external view returns (bool consumed);

    /**
     * @notice External view function for getting required stipends for releasing tokens as a
     * fallback on claims where withdrawals do not succeed. Any requested withdrawal is first
     * attempted using half of available gas. If it fails, then a direct 6909 transfer will be
     * performed as long as the remaining gas left exceeds the benchmarked stipend.
     * @return nativeTokenStipend The gas stipend required for native token withdrawals.
     * @return erc20TokenStipend  The gas stipend required for ERC20 token withdrawals.
     */
    function getRequiredWithdrawalFallbackStipends()
        external
        view
        returns (uint256 nativeTokenStipend, uint256 erc20TokenStipend);

    /**
     * @notice External view function for returning the domain separator of the contract.
     * @return domainSeparator A bytes32 representing the domain separator for the contract.
     */
    function DOMAIN_SEPARATOR() external view returns (bytes32 domainSeparator);

    /**
     * @notice External pure function for returning the name of the contract.
     * @return A string representing the name of the contract.
     */
    function name() external pure returns (string memory);

    error InvalidToken(address token);
    error Expired(uint256 expiration);
    error InvalidSignature();
    error PrematureWithdrawal(uint256 id);
    error ForcedWithdrawalFailed();
    error ForcedWithdrawalAlreadyDisabled(address account, uint256 id);
    error UnallocatedTransfer(address operator, address from, address to, uint256 id, uint256 amount);
    error InvalidBatchAllocation();
    error InvalidRegistrationProof(address allocator);
    error InvalidBatchDepositStructure();
    error AllocatedAmountExceeded(uint256 allocatedAmount, uint256 providedAmount);
    error InvalidScope(uint256 id);
    error InvalidDepositTokenOrdering();
    error InvalidDepositBalanceChange();
    error Permit2CallFailed();
    error ReentrantCall(address existingCaller);
    error InconsistentAllocators();
    error InvalidAllocation(address allocator);
    error ChainIndexOutOfRange();
    error InvalidEmissaryAssignment();
    error EmissaryAssignmentUnavailable(uint256 assignableAt);
    error InvalidLockTag();
}

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

import { IAllocator } from "./IAllocator.sol";
import { Lock } from "../types/EIP712Types.sol";

interface IOnChainAllocation is IAllocator {
    error InvalidPreparation();
    error InvalidRegistration(address sponsor, bytes32 claimHash);

    /// @notice Emitted when a tokens are successfully allocated
    /// @param sponsor The address of the sponsor
    /// @param commitments The commitments of the allocations
    /// @param nonce The nonce of the allocation
    /// @param expires The expiration of the allocation
    /// @param claimHash The hash of the allocation
    event Allocated(address indexed sponsor, Lock[] commitments, uint256 nonce, uint256 expires, bytes32 claimHash);

    /**
     * @notice Allows to create an allocation on behalf of a recipient without the contract being in control over the funds.
     * @notice Will typically be used in combination with `batchDepositAndRegisterFor` on the compact.
     * @dev Must be called before `executeAllocation` to ensure a valid balance change has occurred for the recipient.
     * @param recipient The account to receive the tokens.
     * @param idsAndAmounts The ids and amounts to allocate.
     * @param arbiter The account tasked with verifying and submitting the claim.
     * @param expires The time at which the claim expires.
     * @param typehash The typehash of the claim.
     * @param witness The witness of the claim.
     * @return nonce The next valid nonce. It is only guaranteed that the nonce is valid within the same transaction..
     */
    function prepareAllocation(
        address recipient,
        uint256[2][] calldata idsAndAmounts,
        address arbiter,
        uint256 expires,
        bytes32 typehash,
        bytes32 witness,
        bytes calldata orderData
    ) external returns (uint256 nonce);

    /**
     * @notice Executes an allocation on behalf of a recipient.
     * @dev Must be called after `prepareAllocation` to ensure a valid balance change has occurred for the recipient.
     * @param recipient The account to receive the tokens.
     * @param idsAndAmounts The ids and amounts to allocate.
     * @param arbiter The account tasked with verifying and submitting the claim.
     * @param expires The time at which the claim expires.
     * @param typehash The typehash of the claim.
     * @param witness The witness of the claim.
     */
    function executeAllocation(
        address recipient,
        uint256[2][] calldata idsAndAmounts,
        address arbiter,
        uint256 expires,
        bytes32 typehash,
        bytes32 witness,
        bytes calldata orderData
    ) external;
}

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

import { ComponentsById, BatchClaimComponent } from "./Components.sol";

struct AllocatedBatchTransfer {
    bytes allocatorData; // Authorization from the allocator.
    uint256 nonce; // A parameter to enforce replay protection, scoped to allocator.
    uint256 expires; // The time at which the transfer or withdrawal expires.
    ComponentsById[] transfers; // The recipients and amounts of each transfer for each ID.
}

struct BatchClaim {
    bytes allocatorData; // Authorization from the allocator.
    bytes sponsorSignature; // Authorization from the sponsor.
    address sponsor; // The account to source the tokens from.
    uint256 nonce; // A parameter to enforce replay protection, scoped to allocator.
    uint256 expires; // The time at which the claim expires.
    bytes32 witness; // Hash of the witness data.
    string witnessTypestring; // Witness typestring appended to existing typestring.
    BatchClaimComponent[] claims; // The claim token IDs, recipients and amounts.
}

library BatchClaimsLib {
    /**
     * @notice Returns the raw calldata pointer to the batch claim.
     * @param claim The batch claim to get the raw pointer of.
     * @return rawClaimPtr The raw pointer to the batch claim.
     */
    function asRawPtr(BatchClaim calldata claim) internal pure returns (uint256 rawClaimPtr) {
        assembly {
            rawClaimPtr := claim
        }
    }
}

File 15 of 41 : Components.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

struct Component {
    uint256 claimant; // The lockTag + recipient of the transfer or withdrawal.
    uint256 amount; // The amount of tokens to transfer or withdraw.
}

struct ComponentsById {
    uint256 id; // The token ID of the ERC6909 token to transfer or withdraw.
    Component[] portions; // claimants and amounts.
}

struct TransferComponent {
    uint256 id; // The token ID of the ERC6909 token to transfer or withdraw.
    uint256 amount; // The token amount to transfer or withdraw.
}

struct BatchClaimComponent {
    uint256 id; // The token ID of the ERC6909 token to allocate.
    uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens.
    Component[] portions; // claimants and amounts.
}

File 16 of 41 : ITribunalCallback.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import {Lock} from "the-compact/src/types/EIP712Types.sol";
import {FillRequirement} from "../types/TribunalStructs.sol";

/**
 * @title ITribunalCallback
 * @custom:security-contact [email protected]
 * @notice Interface for filler contracts that can receive callbacks from Tribunal during single-chain fills.
 * @dev Called after claiming tokens from The Compact but before transferring fill tokens to the recipient and
 * potentially triggering a recipient callback.
 */
interface ITribunalCallback {
    /**
     * @notice Callback function to be called by the Tribunal contract to the filler.
     * @dev At this point, the filler has already received the claimed tokens and must
     * supply the actual fill amounts of each fill token to Tribunal before exiting the callback.
     * @param claimHash The claim hash of the associated compact that has been claimed.
     * @param commitments The resource lock commitments provided by the sponsor.
     * @param claimedAmounts The actual amounts claimed to complete the fill.
     * @param fillRequirements Array of fill requirements specifying tokens, minimum amounts, and realized amounts.
     */
    function tribunalCallback(
        bytes32 claimHash,
        Lock[] calldata commitments,
        uint256[] calldata claimedAmounts,
        FillRequirement[] calldata fillRequirements
    ) external;
}

File 17 of 41 : IDispatchCallback.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import {BatchCompact} from "the-compact/src/types/EIP712Types.sol";

/**
 * @title IDispatchCallback
 * @custom:security-contact [email protected]
 * @notice Interface for contracts that can receive dispatch callbacks from Tribunal after fills.
 * @dev Implementers must return the correct function selector to confirm successful execution.
 */
interface IDispatchCallback {
    /**
     * @notice Callback function to be called by the Tribunal contract after a fill is completed.
     * @param chainId The chain ID the dispatch callback is intended to interact with.
     * @param compact The compact parameters from the fill.
     * @param mandateHash The mandate hash from the fill.
     * @param claimHash The claim hash of the compact that can be claimed on performing the fill.
     * @param claimant The bytes32 value representing the claimant (lock tag ++ address).
     * @param claimReductionScalingFactor The scaling factor applied to claim amounts (1e18 if no reduction).
     * @param claimAmounts The actual amounts of tokens claimed (after any reductions).
     * @param context Arbitrary context data provided by the filler.
     * @return This function selector to confirm successful execution.
     */
    function dispatchCallback(
        uint256 chainId,
        BatchCompact calldata compact,
        bytes32 mandateHash,
        bytes32 claimHash,
        bytes32 claimant,
        uint256 claimReductionScalingFactor,
        uint256[] calldata claimAmounts,
        bytes calldata context
    ) external payable returns (bytes4);
}

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

import {BatchCompact, Lock} from "the-compact/src/types/EIP712Types.sol";
import {
    FillParameters,
    FillComponent,
    Adjustment,
    Mandate,
    RecipientCallback,
    FillRecipient,
    DispatchParameters,
    DispositionDetails,
    BatchClaim,
    ArgDetail
} from "../types/TribunalStructs.sol";

/**
 * @title ITribunal
 * @custom:security-contact [email protected]
 * @notice Interface for the Tribunal contract that runs competitive auctions for claims against resource locks.
 * Integrates with The Compact for settling claims after fills occur.
 * @dev Provides methods for filling, cancelling, dispatching, and querying auction results with dynamic pricing
 * based on a combination of priority gas auctions (PGA), time-based price curves, and supplemental adjustments.
 */
interface ITribunal {
    // ======== Events ========
    /**
     * @notice Emitted when a standard fill is successfully executed.
     * @dev This event is emitted for all fills using the fill() or fillAndDispatch() functions.
     * @param sponsor The address that created the compact to be claimed.
     * @param claimant The bytes32 value representing the claimant (lock tag ++ address).
     * @param claimHash The hash of the compact being claimed.
     * @param fillRecipients Array of fill amounts and their corresponding recipients.
     * @param claimAmounts The amounts of tokens to be claimed on the claim chain.
     * @param targetBlock The auction start block number as provided on the adjustment.
     */
    event Fill(
        address indexed sponsor,
        bytes32 indexed claimant,
        bytes32 claimHash,
        FillRecipient[] fillRecipients,
        uint256[] claimAmounts,
        uint256 targetBlock
    );

    /**
     * @notice Emitted when an atomic same-chain claim and fill is successfully executed.
     * @dev This event is emitted only for claimAndFill() operations where the claim and fill occur on the same chain atomically.
     * @param sponsor The address that created the claimed compact.
     * @param claimant The bytes32 value representing the claimant (lock tag ++ address).
     * @param claimHash The hash of the claimed compact.
     * @param fillRecipients Array of fill amounts and their corresponding recipients.
     * @param claimAmounts The amounts of tokens claimed.
     * @param targetBlock The auction start block number as provided on the adjustment.
     */
    event FillWithClaim(
        address indexed sponsor,
        bytes32 indexed claimant,
        bytes32 claimHash,
        FillRecipient[] fillRecipients,
        uint256[] claimAmounts,
        uint256 targetBlock
    );

    /**
     * @notice Emitted when a compact is cancelled by its sponsor.
     * @param sponsor The address that cancelled the compact.
     * @param claimHash The hash of the cancelled compact.
     */
    event Cancel(address indexed sponsor, bytes32 claimHash);

    /**
     * @notice Emitted when a dispatch callback is executed to relay fill results.
     * @dev This event is emitted when using fillAndDispatch(), dispatch(), or cancelAndDispatch() functions.
     * @param dispatchTarget The address that received the dispatch callback.
     * @param chainId The target chain ID for the dispatch message.
     * @param claimant The bytes32 value representing the claimant (or sponsor if cancelled).
     * @param claimHash The hash of the compact that was filled or cancelled.
     */
    event Dispatch(
        address indexed dispatchTarget,
        uint256 indexed chainId,
        bytes32 indexed claimant,
        bytes32 claimHash
    );

    // ======== Custom Errors ========
    error InvalidGasPrice();
    error AlreadyFilled();
    error InvalidTargetBlockDesignation();
    error InvalidTargetBlock(uint256 blockNumber, uint256 targetBlockNumber);
    error NotSponsor();
    error ReentrancyGuard();
    error InvalidRecipientCallbackLength();
    error ValidityConditionsNotMet();
    error InvalidFillBlock();
    error InvalidAdjustment();
    error InvalidFillHashArguments();
    error InvalidRecipientCallback();
    error InvalidChainId();
    error InvalidCommitmentsArray();
    error InvalidDispatchCallback();
    error DispatchNotAvailable();

    /**
     * @notice Executes a standard fill.
     * @dev Fillers must provide all required output tokens and have granted token approvals to Tribunal.
     * Native tokens (ETH) must be included as msg.value. This is the core execution method for most fills.
     * Works for cross-chain fills where claim and fill occur on different chains, and for same-chain fills
     * when asynchronous operation is acceptable.
     * @param compact The compact parameters and constraints.
     * @param mandate The fill conditions and amount derivation parameters.
     * @param adjustment The adjustment provided by the adjuster for the fill (includes adjuster and authorization).
     * @param fillHashes An array of the hashes of each fill in the mandate.
     * @param claimant The recipient of claimed tokens on the claim chain (lock tag ++ address).
     * @param fillBlock The block number to target for the fill (0 uses current block, otherwise must match current block).
     * @return claimHash The derived claim hash.
     * @return mandateHash The derived mandate hash.
     * @return fillAmounts The amounts of tokens to be filled for each component.
     * @return claimAmounts The amounts of each token to be claimed.
     */
    function fill(
        BatchCompact calldata compact,
        FillParameters calldata mandate,
        Adjustment calldata adjustment,
        bytes32[] calldata fillHashes,
        bytes32 claimant,
        uint256 fillBlock
    )
        external
        payable
        returns (
            bytes32 claimHash,
            bytes32 mandateHash,
            uint256[] memory fillAmounts,
            uint256[] memory claimAmounts
        );

    /**
     * @notice Executes a standard fill and immediately triggers a filler-specified dispatch callback.
     * @dev This function combines fill execution with immediate cross-chain message relay. The filler chooses
     * the dispatch target and parameters, which are not signed by the sponsor. Ideal for relaying fill results
     * to cross-chain messaging systems via outbox or adapter contracts. Not needed for read-based cross-chain
     * systems that can query events or state directly from the source chain.
     * @param compact The compact parameters and constraints.
     * @param mandate The fill conditions and amount derivation parameters.
     * @param adjustment The adjustment provided by the adjuster for the fill (includes adjuster and authorization).
     * @param fillHashes An array of the hashes of each fill in the mandate.
     * @param claimant The recipient of claimed tokens on the claim chain (lock tag ++ address).
     * @param fillBlock The block number to target for the fill (0 uses current block, must match current block).
     * @param dispatch The dispatch callback parameters (target, chainId, value, context).
     * @return claimHash The derived claim hash.
     * @return mandateHash The derived mandate hash.
     * @return fillAmounts The amounts of tokens to be filled for each component.
     * @return claimAmounts The amounts of each token to be claimed.
     */
    function fillAndDispatch(
        BatchCompact calldata compact,
        FillParameters calldata mandate,
        Adjustment calldata adjustment,
        bytes32[] calldata fillHashes,
        bytes32 claimant,
        uint256 fillBlock,
        DispatchParameters calldata dispatch
    )
        external
        payable
        returns (
            bytes32 claimHash,
            bytes32 mandateHash,
            uint256[] memory fillAmounts,
            uint256[] memory claimAmounts
        );

    /**
     * @notice Executes an atomic same-chain fill where the claim and fill occur in a single transaction.
     * @dev Only works when the claim chain equals the fill chain. Operates atomically, optimistically releasing
     * input tokens to the filler first via a callback, then verifying they provided the output. The filler receives
     * the input tokens during the callback and can use them to generate the required output (flash loan-style).
     * Ideal for same-chain token swaps with atomic execution guarantees, capturing arbitrage opportunities, or
     * any scenarios requiring transaction-level atomicity. Note that the `tribunalCallback` function must be
     * implemented by the caller, and that all indicated fill tokens must be provided to Tribunal by the time the
     * callback completes.
     * @param claim The batch claim containing compact parameters, sponsor signature, and allocator signature.
     * @param mandate The fill conditions and amount derivation parameters.
     * @param adjustment The adjustment provided by the adjuster for the fill (includes adjuster and authorization).
     * @param fillHashes An array of the hashes of each fill in the mandate.
     * @param claimant The recipient of claimed tokens on the claim chain (lock tag ++ address).
     * @param fillBlock The block number to target for the fill (0 uses current block, must match current block).
     * @return claimHash The derived claim hash.
     * @return mandateHash The derived mandate hash.
     * @return fillAmounts The amounts of tokens to be filled for each component.
     * @return claimAmounts The amounts of tokens to be claimed.
     */
    function claimAndFill(
        BatchClaim calldata claim,
        FillParameters calldata mandate,
        Adjustment calldata adjustment,
        bytes32[] calldata fillHashes,
        bytes32 claimant,
        uint256 fillBlock
    )
        external
        payable
        returns (
            bytes32 claimHash,
            bytes32 mandateHash,
            uint256[] memory fillAmounts,
            uint256[] memory claimAmounts
        );

    /**
     * @notice Relays fill results after the fact by triggering a dispatch callback for a previously completed fill.
     * @dev This function queries the stored claimant and scaling factor, reconstructs claim amounts, and triggers
     * the dispatch callback. Used for batch relaying of multiple fills, retrying failed cross-chain message dispatch,
     * or delayed dispatch for systems with specific timing requirements. Only works on previously completed fills
     * where a claimant has already been recorded. Not needed for read-based systems that can query state directly.
     * @param compact The compact parameters from the original fill.
     * @param mandateHash The mandate hash from the original fill.
     * @param dispatch The dispatch callback parameters (target, chainId, value, context).
     * @return claimHash The claim hash derived from the compact and mandate.
     * @return claimAmounts The amounts of tokens claimed.
     */
    function dispatch(
        BatchCompact calldata compact,
        bytes32 mandateHash,
        DispatchParameters calldata dispatch
    ) external payable returns (bytes32 claimHash, uint256[] memory claimAmounts);

    /**
     * @notice Handles token receipt on destination chains after bridging, with race condition protection.
     * @dev This function is typically triggered by a recipient callback from a same-chain fill on the source chain.
     * It implements multi-modal behavior based on parameters and state:
     * 1. If source claim filled: forwards tokens to the filler who won the target chain auction
     * 2. If empty lock tag: performs direct transfer to recipient
     * 3. If zero mandate hash: deposits to The Compact without registration
     * 4. If nonce is zero: triggers on-chain allocation flow
     * 5. Otherwise: performs standard compact deposit and registration for follow-up auction
     * Race condition protection ensures that if a direct cross-chain fill and a same-chain fill + bridge both
     * execute, the filler who provided output tokens still receives their input tokens.
     * @param sourceClaimHash The claim hash of the source compact on the target chain.
     * @param compact The parameters to register a follow-up compact.
     * @param mandateHash The mandate hash of the follow-up compact (bytes32(0) for no registration).
     * @param recipient The recipient of directly forwarded tokens (defaults to sponsor if address(0)).
     * @param context The context forwarded to the allocator in an on-chain allocation.
     * @return registeredClaimHash The hash of the newly-registered compact (bytes32(0) if no registration).
     */
    function settleOrRegister(
        bytes32 sourceClaimHash,
        BatchCompact calldata compact,
        bytes32 mandateHash,
        address recipient,
        bytes calldata context
    ) external payable returns (bytes32 registeredClaimHash);

    /**
     * @notice Cancels an unfilled auction on the target chain (fill chain).
     * @dev Must be called by the sponsor. CANNOT cancel on the origin chain (claim chain) as a filler may have
     * already executed the fill on the target chain and is waiting for proof to claim their input tokens. CAN cancel
     * on the target chain before a fill occurs, preventing other fillers from executing the auction (analogous to a
     * self-fill where no tokens need to be supplied). Stores type(uint256).max as a cancellation flag.
     * @param compact The compact parameters.
     * @param mandateHash The mandate hash of the claim to cancel.
     * @return claimHash The hash of the cancelled claim.
     */
    function cancel(BatchCompact calldata compact, bytes32 mandateHash)
        external
        returns (bytes32 claimHash);

    /**
     * @notice Cancels an unfilled auction and triggers a dispatch callback to notify cross-chain systems.
     * @dev Must be called by the sponsor. Performs the same cancellation as cancel(), but additionally dispatches
     * a message with zero claim amounts and the sponsor designated as the claimant. This enables notifying cross-chain
     * systems of the cancellation, allowing The Compact to consume the nonce so allocators can securely deallocate
     * committed resource locks on those chains.
     * @param compact The compact parameters and constraints.
     * @param mandateHash The mandate hash of the claim to cancel.
     * @param dispatch The dispatch callback parameters (target, chainId, value, context).
     * @return claimHash The hash of the cancelled claim.
     */
    function cancelAndDispatch(
        BatchCompact calldata compact,
        bytes32 mandateHash,
        DispatchParameters calldata dispatch
    ) external payable returns (bytes32 claimHash);

    /**
     * @notice Returns EIP-712 witness structure details for The Compact integration.
     * @dev The witness (or mandate) typestring is used when registering compacts with The Compact, enabling selective
     * reveal of nested data. This provides the structure for embedding Tribunal-specific witness data within
     * The Compact's EIP-712 structure.
     * @return witnessTypeString The EIP-712 type string for the mandate witness.
     * @return details An array of argument details mapping tokens and amounts for witness validation.
     */
    function getCompactWitnessDetails()
        external
        pure
        returns (string memory witnessTypeString, ArgDetail[] memory details);

    /**
     * @notice Checks the fill status of a claim.
     * @dev Returns the claimant's identifier (lock tag ++ address) if filled, the sponsor's identifier if cancelled,
     * or zero if unfilled.
     * @param claimHash The hash of the claim to check.
     * @return The claimant bytes32 value if filled, sponsor if cancelled, or bytes32(0) if unfilled.
     */
    function filled(bytes32 claimHash) external view returns (bytes32);

    /**
     * @notice Returns the claim reduction scaling factor for a given claim hash.
     * @dev In exact-out mode, this factor indicates how much claim amounts were reduced due to competitive bidding.
     * Returns 1e18 if no reduction occurred, 0 if cancelled, or the actual reduction factor if claims were reduced.
     * @param claimHash The claim hash to query.
     * @return scalingFactor The scaling factor (1e18 if not set, 0 if cancelled, or actual factor if reduced).
     */
    function claimReductionScalingFactor(bytes32 claimHash)
        external
        view
        returns (uint256 scalingFactor);

    /**
     * @notice Queries multiple claims at once, returning both claimant and scaling factor for each.
     * @dev Provides batch querying functionality for multi-claim status checks.
     * @param claimHashes Array of claim hashes to query.
     * @return details Array of disposition details containing the claimant identifier and scaling factor for each claim.
     */
    function getDispositionDetails(bytes32[] calldata claimHashes)
        external
        view
        returns (DispositionDetails[] memory details);

    /**
     * @notice Derives fill amounts and claim amounts from fill components.
     * @param maximumClaimAmounts The maximum amounts to claim.
     * @param components The fill components.
     * @param priceCurve The price curve to apply.
     * @param targetBlock The target block number.
     * @param fillBlock The fill block number.
     * @param baselinePriorityFee The baseline priority fee.
     * @param scalingFactor The scaling factor.
     * @return fillAmounts The derived fill amounts for each component.
     * @return claimAmounts The derived claim amounts.
     */
    function deriveAmountsFromComponents(
        Lock[] calldata maximumClaimAmounts,
        FillComponent[] calldata components,
        uint256[] memory priceCurve,
        uint256 targetBlock,
        uint256 fillBlock,
        uint256 baselinePriorityFee,
        uint256 scalingFactor
    ) external view returns (uint256[] memory fillAmounts, uint256[] memory claimAmounts);

    /**
     * @notice Derives the mandate hash using EIP-712 typed data hashing.
     * @dev The mandate contains the adjuster address and an array of possible fills that enable conditional execution.
     * @param mandate The mandate containing adjuster and fills array.
     * @return The derived mandate hash.
     */
    function deriveMandateHash(Mandate calldata mandate) external view returns (bytes32);

    /**
     * @notice Derives the hash of an array of fills using EIP-712 typed data hashing.
     * @dev Each fill in the array is hashed individually, then the array of hashes is hashed together.
     * @param fills The array of fill parameters.
     * @return The derived fills array hash.
     */
    function deriveFillsHash(FillParameters[] calldata fills) external view returns (bytes32);

    /**
     * @notice Derives a fill hash using EIP-712 typed data hashing.
     * @dev The fill hash includes chain ID, tribunal address, expiration, components, pricing parameters,
     * price curve, recipient callback, and salt for uniqueness.
     * @param targetFill The fill parameters including all pricing and execution conditions.
     * @return The derived fill hash.
     */
    function deriveFillHash(FillParameters calldata targetFill) external view returns (bytes32);

    /**
     * @notice Derives a fill component hash using EIP-712 typed data hashing.
     * @dev Each fill component represents an individual output token with its own token address, amount,
     * recipient, and scaling flag.
     * @param component The fill component with token, amount, recipient, and applyScaling flag.
     * @return The derived fill component hash.
     */
    function deriveFillComponentHash(FillComponent calldata component)
        external
        pure
        returns (bytes32);

    /**
     * @notice Derives the hash of the fill components array.
     * @param components The fill components array.
     * @return The hash of the fill components array.
     */
    function deriveFillComponentsHash(FillComponent[] calldata components)
        external
        pure
        returns (bytes32);

    /**
     * @notice Derives a recipient callback hash using EIP-712 typed data hashing.
     * @dev The recipient callback is signed by the sponsor as part of the mandate. The array must be empty
     * or contain exactly one element. Used for bridging fill tokens to destination chains or triggering
     * follow-up compacts.
     * @param recipientCallback The recipient callback array (empty or single element).
     * @return The derived recipient callback hash.
     */
    function deriveRecipientCallbackHash(RecipientCallback[] calldata recipientCallback)
        external
        pure
        returns (bytes32);

    /**
     * @notice Derives the claim hash from compact parameters and mandate hash.
     * @dev The claim hash uniquely identifies a specific auction instance combining The Compact's
     * commitment structure with Tribunal's mandate.
     * @param compact The compact parameters (arbiter, sponsor, nonce, expires, commitments).
     * @param mandateHash The derived mandate hash.
     * @return The derived claim hash.
     */
    function deriveClaimHash(BatchCompact calldata compact, bytes32 mandateHash)
        external
        pure
        returns (bytes32);

    /**
     * @notice Simulates price derivation (fill amounts and claim amounts) for an analogous auction.
     * @dev Derives fill and claim amounts based on mandate parameters and current conditions, incorporating
     * all three pricing mechanisms: priority gas auctions (PGA), time-based price curves, and supplemental curves.
     * In exact-in mode (scalingFactor >= 1e18), fill amounts increase and claim amounts stay at maximum.
     * In exact-out mode (scalingFactor < 1e18), claim amounts decrease and fill amounts stay at minimum.
     * @param maximumClaimAmounts The maximum claim amounts for each commitment (input tokens).
     * @param priceCurve The time-based price curve (array of duration/scaling-factor pairs).
     * @param targetBlock The auction start block number.
     * @param fillBlock The block where the fill is performed.
     * @param minimumFillAmount The minimum fill amount (output tokens).
     * @param baselinePriorityFee The baseline priority fee threshold in wei.
     * @param scalingFactor The PGA scaling factor (1e18 = neutral, >1e18 = exact-in, <1e18 = exact-out).
     * @return fillAmount The derived fill amount.
     * @return claimAmounts The derived claim amounts.
     */
    function deriveAmounts(
        Lock[] calldata maximumClaimAmounts,
        uint256[] memory priceCurve,
        uint256 targetBlock,
        uint256 fillBlock,
        uint256 minimumFillAmount,
        uint256 baselinePriorityFee,
        uint256 scalingFactor
    ) external view returns (uint256 fillAmount, uint256[] memory claimAmounts);

    /**
     * @notice Returns the name of this contract.
     * @return The contract name.
     */
    function name() external pure returns (string memory);

    /**
     * @notice External view function for reading a value from persistent storage.
     * @param slot The storage slot to read from.
     * @return The value stored in the specified persistent storage slot.
     */
    function extsload(bytes32 slot) external view returns (bytes32);

    /**
     * @notice External view function for reading multiple values from persistent storage.
     * @param slots An array of storage slots to read from.
     * @return An array of values stored in the specified persistent storage slots.
     */
    function extsload(bytes32[] calldata slots) external view returns (bytes32[] memory);

    /**
     * @notice Returns the address that initiated the current protected call sequence.
     * @dev Reads from transient storage to expose the reentrancy guard state. This is useful
     * for determining if execution is currently within a nonReentrant context and for
     * verifying the origination point of the current call.
     * @return lockHolder The address of the original caller when executing within a
     * nonReentrant function, or address(0) if the reentrancy guard is not currently active.
     */
    function reentrancyGuardStatus() external view returns (address lockHolder);
}

File 19 of 41 : TribunalStructs.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import {BatchCompact} from "the-compact/src/types/EIP712Types.sol";

// Overview of the sequence of steps:
//  1) sponsor deposits and registers a compact on the source chain assigning an adjuster, a cross-chain fill, and a source-chain fallback action that will trigger a deposit and registration of a target-chain compact. Allocator ensures that deposited tokens are allocated.
//  2) adjuster cosigns an adjustment for the cross-chain fill (if they do not cosign, sponsor signs a new compact or withdraws)
//  3) cross-chain fill is revealed and active (source chain and target chain actions remain hidden)
//    3a) filler provides tokens on target chain, then claims tokens on source chain
//    3b) sponsor cancels early by submitting a transaction on the target chain before the fill occurs
//    3c) no filler takes the cross-chain order in time, proceed to step 4
//  4) adjuster cosigns an adjustment for the source chain fill (if they do not cosign, sponsor signs a new compact or withdraws)
//  5) source chain fill is revealed and active (target chain action remains hidden, though input token and expiration are revealed)
//    5a) filler takes input tokens and provides intermediate output tokens on source chain, then triggers bridge to tribunal on target chain that in turn triggers desposit + register (+ allocate if needed) on target chain (mandate remains hidden), proceed to step 6
//    5b) sponsor cancels early by submitting a transaction on the target chain — note that step 5a still may occur
//    5c) no filler takes the source chain order in time, sponsor signs a new compact or withdraws tokens
//  6) bridge lands and bridged tokens are deposited into the compact on target chain with accompanying compact registration — note that if a filler completed step 3a then tokens are sent to them instead, and if sponsor completed step 3b then tokens are sent to them directly
//   7a) sponsor claims deposited tokens directly, cancelling early
//   7b) adjuster cosigns an adjustment for the target chain fill (if they do not cosign, sponsor signs a new compact or withdraws)
//   Note: important to handle the case where the bridge transaction is not completed and funds need to be withdrawn from the bridge contract on the source chain and returned to the sponsor
//  8) target chain fill is revealed and active
//   8a) filler claims deposited tokens in exchange for providing output tokens to recipient
//   8b) sponsor claims deposited tokens directly, cancelling
//   8b) no filler takes the target chain order in time, proceed to step 9
//  9) tokens are deallocated and available in The Compact on target chain
//   9a) sponsor signs a new compact to perform a modified target chain swap
//   9b) sponsor signs a new compact to perform a cross-chain swap back to the original source chain (basically return to step 1 with target and source swapped) — note that this could also be part of the originally registered target chain compact and performed automatically
//   9c) sponsor manually withdraws tokens on target chain

// Parent mandate signed by the sponsor on source chain. Note that the EIP-712 payload differs slightly from the structs declared here (mainly around utilizing full mandates rather than mandate hashes).
struct Mandate {
    address adjuster;
    FillParameters[] fills; // Arbitrary-length array; note that in EIP-712 payload this is Mandate_Fill
}

// Mandate_Fill in EIP-712 payload
struct FillParameters {
    uint256 chainId; // Same-chain if value matches chainId(), otherwise cross-chain
    address tribunal; // Contract where the fill is performed.
    uint256 expires; // Fill expiration timestamp.
    FillComponent[] components; // Fill components.
    uint256 baselinePriorityFee; // Base fee threshold where scaling kicks in.
    uint256 scalingFactor; // Fee scaling multiplier (1e18 baseline).
    uint256[] priceCurve; // Block durations and uint240 additional scaling factors per each duration.
    RecipientCallback[] recipientCallback; // Array of length 0 or 1; note that in EIP-712 payload this is Mandate_RecipientCallback[]
    bytes32 salt;
}

// Mandate_FillComponent in EIP-712 payload
struct FillComponent {
    address fillToken; // Token to be provided (address(0) for native).
    uint256 minimumFillAmount; // Minimum fill amount.
    address recipient; // Recipient of the tokens — address(0) or tribunal indicate that funds will be pulled by the directive.
    bool applyScaling; // Whether or not to apply scaling factor to the minimum amount.
}

// If a callback is specified, tribunal will follow up with a call to the first recipient with fill details (including realized fill amount), a new compact and hash of an accompanying mandate, a target chainId, and context
// Note that this does not directly map to the EIP-712 payload (which contains a Mandate_BatchCompact containing the full `Mandate mandate` rather than BatchCompact + mandateHash)
// Mandate_RecipientCallback in EIP-712 payload
struct RecipientCallback {
    uint256 chainId;
    BatchCompact compact;
    bytes32 mandateHash;
    bytes context;
}

// Arguments signed for by adjuster.
struct Adjustment {
    address adjuster; // Assigned adjuster for the fill (not included in EIP-712 payload).
    // bytes32 claimHash included in EIP-712 payload but not provided as an argument.
    uint256 fillIndex;
    uint256 targetBlock;
    uint256[] supplementalPriceCurve; // Additional scaling factor specified duration on price curve.
    bytes32 validityConditions; // Optional value consisting of a number of blocks past the target and a exclusive filler address.
    bytes adjustmentAuthorization; // Authorization from the adjuster (not included in EIP-712 payload).
}

// Struct for event emissions that pairs fill amounts with recipients.
struct FillRecipient {
    uint256 fillAmount;
    address recipient;
}

// Struct for filler callback that contains all fill component details.
struct FillRequirement {
    address fillToken; // Token to be provided (address(0) for native).
    uint256 minimumFillAmount; // Minimum specified fill amount.
    uint256 realizedFillAmount; // Actual fill amount that must be provided.
}

// Struct for dispatch callback parameters.
struct DispatchParameters {
    uint256 chainId; // Chain ID the dispatch callback is intended to interact with.
    address target; // Address that will receive the dispatch callback.
    uint256 value; // Amount of native tokens to send with the callback.
    bytes context; // Arbitrary context data to pass to the callback.
}

// A disposition refers to a successful fill. Tribunal allows the filler to assign
// an indicated claimant and scaling factor that should be applied to a subsequent
// claim, though the arbiter is ultimately responsible for their application.
struct DispositionDetails {
    bytes32 claimant;
    uint256 scalingFactor;
}

struct BatchClaim {
    BatchCompact compact;
    bytes sponsorSignature; // Authorization from the sponsor
    bytes allocatorSignature; // Authorization from the allocator
}

struct ArgDetail {
    string tokenPath;
    string argPath;
    string description;
}

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

/**
 * @title DomainLib
 * @custom:security-contact [email protected]
 * @notice Library contract implementing logic for deriving domain hashes.
 */
library DomainLib {
    /// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`.
    bytes32 internal constant _DOMAIN_TYPEHASH =
        0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;

    /// @dev `keccak256(bytes("Tribunal"))`.
    bytes32 internal constant _NAME_HASH =
        0x0e2a7404936dd29a4a3b49dad6c2f86f8e2da9cf7cf60ef9518bb049b4cb9b44;

    /// @dev `keccak256("1")`.
    bytes32 internal constant _VERSION_HASH =
        0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6;

    /**
     * @notice Internal view function that returns the current domain separator, deriving a new one
     * if the chain ID has changed from the initial chain ID.
     * @param initialDomainSeparator The domain separator derived at deployment time.
     * @param initialChainId         The chain ID at the time of deployment.
     * @return domainSeparator       The current domain separator.
     */
    function toLatest(bytes32 initialDomainSeparator, uint256 initialChainId)
        internal
        view
        returns (bytes32 domainSeparator)
    {
        // Set the initial domain separator as the default domain separator.
        domainSeparator = initialDomainSeparator;

        assembly ("memory-safe") {
            // Derive domain separator again if initial chain ID differs from current one.
            if xor(chainid(), initialChainId) {
                // Retrieve the free memory pointer.
                let m := mload(0x40)

                // Prepare domain data: EIP-712 typehash, name hash, version hash, chain ID, & verifying contract.
                mstore(m, _DOMAIN_TYPEHASH)
                mstore(add(m, 0x20), _NAME_HASH)
                mstore(add(m, 0x40), _VERSION_HASH)
                mstore(add(m, 0x60), chainid())
                mstore(add(m, 0x80), address())

                // Derive the domain separator.
                domainSeparator := keccak256(m, 0xa0)
            }
        }
    }

    /**
     * @notice Internal view function that derives a domain separator for the current chain ID.
     * @return domainSeparator The current domain separator.
     */
    function toCurrentDomainSeparator() internal view returns (bytes32 domainSeparator) {
        assembly ("memory-safe") {
            // Retrieve the free memory pointer.
            let m := mload(0x40)

            // Prepare domain data: EIP-712 typehash, name hash, version hash, chain ID, and verifying contract.
            mstore(m, _DOMAIN_TYPEHASH)
            mstore(add(m, 0x20), _NAME_HASH)
            mstore(add(m, 0x40), _VERSION_HASH)
            mstore(add(m, 0x60), chainid())
            mstore(add(m, 0x80), address())

            // Derive the domain separator.
            domainSeparator := keccak256(m, 0xa0)
        }
    }

    /**
     * @notice Internal pure function that combines a message hash with a domain separator
     * to create a domain-specific hash according to EIP-712.
     * @param messageHash     The EIP-712 hash of the message data.
     * @param domainSeparator The domain separator to combine with the message hash.
     * @return domainHash     The domain-specific hash.
     */
    function withDomain(bytes32 messageHash, bytes32 domainSeparator)
        internal
        pure
        returns (bytes32 domainHash)
    {
        assembly ("memory-safe") {
            // Retrieve and cache the free memory pointer.
            let m := mload(0x40)

            // Prepare the 712 prefix.
            mstore(0, 0x1901)

            // Prepare the domain separator.
            mstore(0x20, domainSeparator)

            // Prepare the message hash and compute the domain hash.
            mstore(0x40, messageHash)
            domainHash := keccak256(0x1e, 0x42)

            // Restore the free memory pointer.
            mstore(0x40, m)
        }
    }
}

File 21 of 41 : IRecipientCallback.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import {BatchCompact} from "../types/TribunalStructs.sol";

/**
 * @title IRecipientCallback
 * @custom:security-contact [email protected]
 * @notice Interface for contracts that can receive callbacks from Tribunal after same-chain fills.
 * @dev Implementers must return the correct function selector to confirm successful execution.
 */
interface IRecipientCallback {
    /**
     * @notice Callback function to be called by the Tribunal contract to the recipient.
     * @param chainId The target chain ID communicated as part of the callback.
     * @param sourceClaimHash The claim hash of the compact that has been claimed.
     * @param sourceMandateHash The mandate hash of the compact that has been claimed.
     * @param fillToken The reward token of the fill.
     * @param fillAmount The actual fill amount that is provided.
     * @param targetCompact The new compact associated with the callback.
     * @param targetMandateHash The mandate hash associated with the new compact.
     * @param context Arbitrary context associated with the callback.
     * @return This function selector to confirm successful execution.
     */
    function tribunalCallback(
        uint256 chainId,
        bytes32 sourceClaimHash,
        bytes32 sourceMandateHash,
        address fillToken,
        uint256 fillAmount,
        BatchCompact calldata targetCompact,
        bytes32 targetMandateHash,
        bytes calldata context
    ) external returns (bytes4);
}

File 22 of 41 : TribunalTypeHashes.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

/* Example payload signed by swapper for a cross-chain swap with a decomposed same-chain swap on source chain + bridge + register same-chain swap on target chain:
{
    arbiter: SOURCE_CHAIN_TRIBUNAL_CONTRACT,
    sponsor: SWAPPER,
    nonce: SOURCE_CLAIM_NONCE,
    expires: SOURCE_CLAIM_EXPIRATION,
    commitments: [
        {
            lockTag: ONCHAIN_ALLOCATOR_LOCK_TAG_WITH_DEFAULT_PARAMS,
            token: SOURCE_CHAIN_UNI,
            amount: 1_000_000_000_000_000_000
        }
    ],
    mandate: {
        adjuster: UNISWAP_TEE,
        fills: [
            {
                chainId: TARGET_CHAIN_ID,
                tribunal: TARGET_CHAIN_TRIBUNAL_CONTRACT,
                expires; CROSS_CHAIN_FILL_EXPIRATION,
                fillToken: TARGET_CHAIN_USDC,
                minimumFillAmount: 10_017_500,
                baselinePriorityFee; 1_000_000_000,
                scalingFactor; 0x00000000000000000000000000000000000000000000000000000de0b6b3a7640005,
                priceCurve: [0x0002000000000000000000000000000000000000000000000de0b6b3a7640002, 0x0003000000000000000000000000000000000000000000000de0b6b3a7640001]
                recipient: SWAPPER,
                recipientCallback: [],
                salt: 0x1234567890123456789012345678901234567890123456789012345678901234
            },
            {
                chainId: SOURCE_CHAIN_ID,
                tribunal: SOURCE_CHAIN_TRIBUNAL_CONTRACT,
                expires; SAME_CHAIN_FILL_EXPIRATION,
                fillToken: ETH,
                minimumFillAmount: 2_404_400_000_000_000,
                baselinePriorityFee: 0,
                scalingFactor: 0x00000000000000000000000000000000000000000000000000000de0b6b3a7640000,
                priceCurve: [0x0002000000000000000000000000000000000000000000000de0b6b3a7640005, 0x0003000000000000000000000000000000000000000000000de0b6b3a7640003]
                recipient: ACROSS_ADAPTER,
                recipientCallback: [
                    {
                        chainId: TARGET_CHAIN_ID,
                        compact: {
                            arbiter: TARGET_CHAIN_TRIBUNAL_CONTRACT,
                            sponsor: SWAPPER,
                            nonce: TARGET_CLAIM_NONCE,
                            expires: TARGET_CLAIM_EXPIRATION,
                            commitments: [
                                {
                                    lockTag: ONCHAIN_ALLOCATOR_LOCK_TAG_WITH_DEFAULT_PARAMS,
                                    token: ETH,
                                    amount: PLACEHOLDER_VALUE_POPULATED_BY_ADAPTER
                                }
                            ],
                            mandate: {
                                adjuster: UNISWAP_TEE,
                                fills: [
                                    {
                                        chainId: TARGET_CHAIN_ID,
                                        tribunal: TARGET_CHAIN_TRIBUNAL_CONTRACT,
                                        expires; TARGET_CHAIN_FILL_EXPIRATION,
                                        fillToken: TARGET_CHAIN_USDC,
                                        minimumFillAmount: 10_010_000,
                                        baselinePriorityFee; 1_000_000_000,
                                        scalingFactor; 0x00000000000000000000000000000000000000000000000000000de0b6b3a7640005,
                                        priceCurve: [0x0002000000000000000000000000000000000000000000000de0b6b3a7640002, 0x0003000000000000000000000000000000000000000000000de0b6b3a7640001]
                                        recipient: SWAPPER,
                                        recipientCallback: [],
                                        salt: 0x1234567890123456789012345678901234567890123456789012345678901234
                                    }
                                ]
                            }
                        },
                        context: "0x"
                    }
                ],
                salt: 0x1234567890123456789012345678901234567890123456789012345678901234
            },
        ]
    }
}
*/

// Type string constants extracted from Tribunal.sol
string constant MANDATE_TYPESTRING =
    "Mandate(address adjuster,Mandate_Fill[] fills)Mandate_BatchCompact(address arbiter,address sponsor,uint256 nonce,uint256 expires,Mandate_Lock[] commitments,Mandate mandate)Mandate_Fill(uint256 chainId,address tribunal,uint256 expires,Mandate_FillComponent[] components,uint256 baselinePriorityFee,uint256 scalingFactor,uint256[] priceCurve,Mandate_RecipientCallback[] recipientCallback,bytes32 salt)Mandate_FillComponent(address fillToken,uint256 minimumFillAmount,address recipient,bool applyScaling)Mandate_Lock(bytes12 lockTag,address token,uint256 amount)Mandate_RecipientCallback(uint256 chainId,Mandate_BatchCompact compact,bytes context)";

string constant MANDATE_FILL_TYPESTRING =
    "Mandate_Fill(uint256 chainId,address tribunal,uint256 expires,Mandate_FillComponent[] components,uint256 baselinePriorityFee,uint256 scalingFactor,uint256[] priceCurve,Mandate_RecipientCallback[] recipientCallback,bytes32 salt)Mandate(address adjuster,Mandate_Fill[] fills)Mandate_BatchCompact(address arbiter,address sponsor,uint256 nonce,uint256 expires,Mandate_Lock[] commitments,Mandate mandate)Mandate_FillComponent(address fillToken,uint256 minimumFillAmount,address recipient,bool applyScaling)Mandate_Lock(bytes12 lockTag,address token,uint256 amount)Mandate_RecipientCallback(uint256 chainId,Mandate_BatchCompact compact,bytes context)";

string constant MANDATE_FILL_COMPONENT_TYPESTRING =
    "Mandate_FillComponent(address fillToken,uint256 minimumFillAmount,address recipient,bool applyScaling)";

string constant MANDATE_RECIPIENT_CALLBACK_TYPESTRING =
    "Mandate_RecipientCallback(uint256 chainId,Mandate_BatchCompact compact,bytes context)Mandate(address adjuster,Mandate_Fill[] fills)Mandate_BatchCompact(address arbiter,address sponsor,uint256 nonce,uint256 expires,Mandate_Lock[] commitments,Mandate mandate)Mandate_Fill(uint256 chainId,address tribunal,uint256 expires,Mandate_FillComponent[] components,uint256 baselinePriorityFee,uint256 scalingFactor,uint256[] priceCurve,Mandate_RecipientCallback[] recipientCallback,bytes32 salt)Mandate_FillComponent(address fillToken,uint256 minimumFillAmount,address recipient,bool applyScaling)Mandate_Lock(bytes12 lockTag,address token,uint256 amount)";

string constant MANDATE_BATCH_COMPACT_TYPESTRING =
    "Mandate_BatchCompact(address arbiter,address sponsor,uint256 nonce,uint256 expires,Mandate_Lock[] commitments,Mandate mandate)Mandate(address adjuster,Mandate_Fill[] fills)Mandate_Fill(uint256 chainId,address tribunal,uint256 expires,Mandate_FillComponent[] components,uint256 baselinePriorityFee,uint256 scalingFactor,uint256[] priceCurve,Mandate_RecipientCallback[] recipientCallback,bytes32 salt)Mandate_FillComponent(address fillToken,uint256 minimumFillAmount,address recipient,bool applyScaling)Mandate_Lock(bytes12 lockTag,address token,uint256 amount)Mandate_RecipientCallback(uint256 chainId,Mandate_BatchCompact compact,bytes context)";

string constant MANDATE_LOCK_TYPESTRING =
    "Mandate_Lock(bytes12 lockTag,address token,uint256 amount)";

string constant COMPACT_WITH_MANDATE_TYPESTRING =
    "BatchCompact(address arbiter,address sponsor,uint256 nonce,uint256 expires,Lock[] commitments,Mandate mandate)Lock(bytes12 lockTag,address token,uint256 amount)Mandate(address adjuster,Mandate_Fill[] fills)Mandate_BatchCompact(address arbiter,address sponsor,uint256 nonce,uint256 expires,Mandate_Lock[] commitments,Mandate mandate)Mandate_Fill(uint256 chainId,address tribunal,uint256 expires,Mandate_FillComponent[] components,uint256 baselinePriorityFee,uint256 scalingFactor,uint256[] priceCurve,Mandate_RecipientCallback[] recipientCallback,bytes32 salt)Mandate_FillComponent(address fillToken,uint256 minimumFillAmount,address recipient,bool applyScaling)Mandate_Lock(bytes12 lockTag,address token,uint256 amount)Mandate_RecipientCallback(uint256 chainId,Mandate_BatchCompact compact,bytes context)";

string constant ADJUSTMENT_TYPESTRING =
    "Adjustment(bytes32 claimHash,uint256 fillIndex,uint256 targetBlock,uint256[] supplementalPriceCurve,bytes32 validityConditions)";

// Typehash constants (hardcoded to reduce init code size)
bytes32 constant MANDATE_TYPEHASH =
    0xd98eceb6e5c7770b3b664a99c269855402fe5255294a30970d25376caea662c6;

bytes32 constant MANDATE_FILL_TYPEHASH =
    0x1d0ee69a7bc1ac54d9a6b38f32ab156fbfe09a9098843d54f89e7b1033533d33;

bytes32 constant MANDATE_FILL_COMPONENT_TYPEHASH =
    0x97a135285706d21a6b74ac159b77b16cea827acc358fc6c33e430ce0a85fe9d6;

bytes32 constant MANDATE_RECIPIENT_CALLBACK_TYPEHASH =
    0xb60a17eb6828a433f2f2fcbeb119166fa25e1fb6ae3866e33952bb74f5055031;

bytes32 constant MANDATE_BATCH_COMPACT_TYPEHASH =
    0x75d7205b7ec9e9b203d9161387d95a46c8440f4530dceab1bb28d4194a586227;

bytes32 constant MANDATE_LOCK_TYPEHASH =
    0xce4f0854d9091f37d9dfb64592eee0de534c6680a5444fd55739b61228a6e0b0;

bytes32 constant COMPACT_TYPEHASH_WITH_MANDATE =
    0xdbbdcf42471b4a26f7824df9f33f0a4f9bb4e7a66be6a31be8868a6cbbec0a7d;

bytes32 constant ADJUSTMENT_TYPEHASH =
    0xe829b2a82439f37ac7578a226e337d334e0ee0da2f05ab63891c19cb84714414;

// Witness typestring (partial string that is provided to The Compact by Tribunal to process claims)
string constant WITNESS_TYPESTRING =
    "address adjuster,Mandate_Fill[] fills)Mandate_BatchCompact(address arbiter,address sponsor,uint256 nonce,uint256 expires,Mandate_Lock[] commitments,Mandate mandate)Mandate_Fill(uint256 chainId,address tribunal,uint256 expires,Mandate_FillComponent[] components,uint256 baselinePriorityFee,uint256 scalingFactor,uint256[] priceCurve,Mandate_RecipientCallback[] recipientCallback,bytes32 salt)Mandate_FillComponent(address fillToken,uint256 minimumFillAmount,address recipient,bool applyScaling)Mandate_Lock(bytes12 lockTag,address token,uint256 amount)Mandate_RecipientCallback(uint256 chainId,Mandate_BatchCompact compact,bytes context";

File 23 of 41 : Scope.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

enum Scope {
    Multichain,
    ChainSpecific
}

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

import { ResetPeriod } from "../types/ResetPeriod.sol";
import { Scope } from "../types/Scope.sol";
import { EfficiencyLib } from "./EfficiencyLib.sol";
import { EfficientHashLib } from "solady/utils/EfficientHashLib.sol";

/**
 * @title IdLib
 * @notice Library contract implementing logic for deriving IDs for allocators and
 * for resource locks, converting between various IDs, and for extracting details
 * related to those IDs. This includes logic for registering allocators and for
 * assigning them an allocator ID.
 */
library IdLib {
    using IdLib for bytes12;
    using IdLib for uint96;
    using IdLib for uint256;
    using IdLib for address;
    using EfficiencyLib for bool;
    using EfficiencyLib for uint96;
    using EfficiencyLib for bytes12;
    using EfficiencyLib for uint256;
    using EfficiencyLib for address;
    using EfficiencyLib for ResetPeriod;
    using EfficiencyLib for Scope;
    using EfficientHashLib for bytes;

    error NoAllocatorRegistered(uint96 allocatorId);
    error AllocatorAlreadyRegistered(uint96 allocatorId, address allocator);

    // Storage slot seed for mapping allocator IDs to allocator addresses.
    uint256 private constant _ALLOCATOR_BY_ALLOCATOR_ID_SLOT_SEED = 0x000044036fc77deaed2300000000000000000000000;

    // keccak256(bytes("AllocatorRegistered(uint96,address)")).
    uint256 private constant _ALLOCATOR_REGISTERED_EVENT_SIGNATURE =
        0xc54dcaa67a8fd7b4a9aa6fd57351934c792613d5ec1acbd65274270e6de8f7e4;

    // Error selectors for NoAllocatorRegistered and AllocatorAlreadyRegistered.
    uint256 private constant _NO_ALLOCATOR_REGISTERED_ERROR_SIGNATURE = 0xcf90c3a8;
    uint256 private constant _ALLOCATOR_ALREADY_REGISTERED_ERROR_SIGNATURE = 0xc18b0e97;

    /**
     * @notice Internal function for registering an allocator. Derives an ID for the
     * allocator and stores the allocator's address for that ID, reverting if an
     * allocator has already been registered for the ID in question.
     * @param allocator The address to register as an allocator.
     * @return allocatorId The derived ID for the registered allocator.
     */
    function register(address allocator) internal returns (uint96 allocatorId) {
        // Derive the allocator ID for the provided allocator address.
        allocatorId = allocator.toAllocatorId();

        assembly ("memory-safe") {
            // Derive storage slot for allocator registration by ID.
            let allocatorSlot := or(_ALLOCATOR_BY_ALLOCATOR_ID_SLOT_SEED, allocatorId)

            // Retrieve the allocator value at the derived storage slot.
            let registeredAllocator := sload(allocatorSlot)

            // Revert if an allocator has already been registered for the ID.
            if registeredAllocator {
                mstore(0, _ALLOCATOR_ALREADY_REGISTERED_ERROR_SIGNATURE)
                mstore(0x20, allocatorId)
                mstore(0x40, registeredAllocator)
                revert(0x1c, 0x44)
            }

            // Store allocator address (sanitize first as an added precaution).
            allocator := shr(0x60, shl(0x60, allocator))
            sstore(allocatorSlot, allocator)

            // Emit AllocatorRegistered(allocatorId, allocator) event.
            mstore(0x00, allocatorId)
            mstore(0x20, allocator)
            log1(0x00, 0x40, _ALLOCATOR_REGISTERED_EVENT_SIGNATURE)
        }
    }

    /**
     * @notice Internal view function for constructing a resource lock ID assuming that the
     * provided allocator has been registered. Derives the allocator ID from the registered
     * allocator, and combines it with the provided scope, reset period, and token address
     * to form a single ID value. Reverts if the allocator is not registered.
     * @param token   The address of the underlying token.
     * @param lockTag The lock tag containing allocator ID, reset period, and scope.
     * @return id     The derived resource lock ID.
     */
    function toIdIfRegistered(address token, bytes12 lockTag) internal view returns (uint256 id) {
        // Derive the allocator ID for the provided allocator address.
        lockTag.toAllocatorId().mustHaveARegisteredAllocator();

        // Derive resource lock ID (pack scope, reset period, allocator ID, & token).
        id = lockTag.asUint256() | token.asUint256();
    }

    /**
     * @notice Internal view function for extracting and validating an allocator ID from
     * a resource lock ID. Reverts if the allocator is not registered.
     * @param id           The resource lock ID to extract from.
     * @return allocatorId The validated allocator ID.
     */
    function toAllocatorIdIfRegistered(uint256 id) internal view returns (uint96 allocatorId) {
        allocatorId = id.toAllocatorId();
        allocatorId.mustHaveARegisteredAllocator();
    }

    /**
     * @notice Internal view function for retrieving an allocator's address from their ID.
     * Reverts if no allocator is registered with the provided ID.
     * @param allocatorId The ID to look up.
     * @return allocator  The registered allocator's address.
     */
    function toRegisteredAllocator(uint96 allocatorId) internal view returns (address allocator) {
        assembly ("memory-safe") {
            // Retrieve allocator from storage based on allocator ID.
            allocator := sload(or(_ALLOCATOR_BY_ALLOCATOR_ID_SLOT_SEED, allocatorId))

            // Revert if no registered allocator is located.
            if iszero(allocator) {
                mstore(0, _NO_ALLOCATOR_REGISTERED_ERROR_SIGNATURE)
                mstore(0x20, allocatorId)
                revert(0x1c, 0x24)
            }
        }
    }

    /**
     * @notice Internal view function that checks if an allocator ID has a registered
     * allocator. Reverts if no allocator is registered.
     * @param allocatorId The allocator ID to check.
     */
    function mustHaveARegisteredAllocator(uint96 allocatorId) internal view {
        assembly ("memory-safe") {
            // Derive storage slot using scope + allocatorId & ensure allocator is set.
            if iszero(sload(or(_ALLOCATOR_BY_ALLOCATOR_ID_SLOT_SEED, allocatorId))) {
                mstore(0, _NO_ALLOCATOR_REGISTERED_ERROR_SIGNATURE)
                mstore(0x20, allocatorId)
                revert(0x1c, 0x24)
            }
        }
    }

    /**
     * @notice Internal view function that checks if an allocator can be registered.
     * Returns true if any of the following are true:
     *  - The caller is the allocator
     *  - The allocator address contains code
     *  - The proof is a valid create2 deployment that derives the allocator address
     *    (e.g. proof must take the form of 0xff ++ factory ++ salt ++ initcode hash)
     * @param allocator The address to check.
     * @param proof     An 85-byte value containing create2 address derivation parameters.
     * @return          Whether the allocator can be registered.
     */
    function canBeRegistered(address allocator, bytes calldata proof) internal view returns (bool) {
        return (msg.sender == allocator).or(allocator.code.length > 0).or(
            proof.length == 85 && (proof[0] == 0xff).and(allocator == address(uint160(uint256(proof.hashCalldata()))))
        );
    }

    /**
     * @notice Internal pure function for building the "lock tag" from an
     * allocatorId, scope, and reset period.
     * @param allocatorId The allocator ID, must be at most 92 bits: 4 bits for the compact flag, 88 bits from the allocator address.
     * @param scope       The scope of the resource lock (multichain or single chain).
     * @param resetPeriod The duration after which the resource lock can be reset.
     * @return lockTag    The lock tag.
     */
    function toLockTag(uint96 allocatorId, Scope scope, ResetPeriod resetPeriod)
        internal
        pure
        returns (bytes12 lockTag)
    {
        // Derive lock tag (pack scope, reset period, & allocator ID).
        assembly {
            lockTag := or(or(shl(255, scope), shl(252, resetPeriod)), shl(160, allocatorId))
        }
    }

    /**
     * @notice Internal pure function for extracting the "lock tag" from an ID.
     * @param id The resource lock ID.
     * @return lockTag The lock tag.
     */
    function toLockTag(uint256 id) internal pure returns (bytes12 lockTag) {
        // Extract the lock tag.
        assembly ("memory-safe") {
            lockTag := shl(160, shr(160, id))
        }
    }

    /**
     * @notice Internal pure function for extracting the last 20 bytes of an
     * underlying uint256 as an address. This represents either the token
     * address (for a resource lock ID) or the claimant address (for a claimant
     * value).
     * @param id The uint256 to extract from.
     * @return   The address.
     */
    function toAddress(uint256 id) internal pure returns (address) {
        return id.asSanitizedAddress();
    }

    /**
     * @notice Internal pure function for creating a new resource lock ID with a
     * different token address.
     * @param id         The resource lock ID to modify.
     * @param token      The new token address.
     * @return updatedId The modified resource lock ID.
     */
    function withReplacedToken(uint256 id, address token) internal pure returns (uint256 updatedId) {
        assembly ("memory-safe") {
            updatedId := or(shl(160, shr(160, id)), shr(96, shl(96, token)))
        }
    }

    /**
     * @notice Internal pure function for creating a new resource lock ID from an
     * existing id and a lock tag.
     * @param id         The resource lock ID to modify.
     * @param lockTag    The new lock tag.
     * @return updatedId The modified resource lock ID.
     */
    function withReplacedLockTag(uint256 id, bytes12 lockTag) internal pure returns (uint256 updatedId) {
        assembly ("memory-safe") {
            updatedId := or(shl(160, shr(160, lockTag)), shr(96, shl(96, id)))
        }
    }

    /**
     * @notice Internal pure function for extracting the scope from a resource lock ID.
     * @param id     The resource lock ID to extract from.
     * @return scope The scope (uppermost bit).
     */
    function toScope(uint256 id) internal pure returns (Scope scope) {
        assembly ("memory-safe") {
            // extract uppermost bit
            scope := shr(255, id)
        }
    }

    /**
     * @notice Internal pure function for extracting the reset period from a resource
     * lock ID.
     * @param id           The resource lock ID to extract from.
     * @return resetPeriod The reset period (bits 252-254).
     */
    function toResetPeriod(uint256 id) internal pure returns (ResetPeriod resetPeriod) {
        assembly ("memory-safe") {
            // extract 2nd, 3rd & 4th uppermost bits
            resetPeriod := and(shr(252, id), 7)
        }
    }

    /**
     * @notice Internal pure function for extracting the reset period from a resource
     * lock tag.
     * @param lockTag      The resource lock tag to extract from.
     * @return resetPeriod The reset period (bits 252-254).
     */
    function toResetPeriod(bytes12 lockTag) internal pure returns (ResetPeriod resetPeriod) {
        assembly ("memory-safe") {
            // extract 2nd, 3rd & 4th uppermost bits
            resetPeriod := and(shr(252, lockTag), 7)
        }
    }

    /**
     * @notice Internal pure function for converting a reset period to its duration in
     * seconds. There are eight distinct reset periods ranging from one second to
     * thirty days. Specific periods include some additional padding:
     *  - One hour is padded by five minutes
     *  - Seven days is padded by one hour
     * @dev No bounds check performed; ensure that the enum value is in range.
     * @param resetPeriod The reset period to convert.
     * @return duration   The duration in seconds.
     */
    function toSeconds(ResetPeriod resetPeriod) internal pure returns (uint256 duration) {
        assembly ("memory-safe") {
            // Bitpacked durations in 24-bit segments:
            // 278d00  094890  015180  000f3c  000258  00003c  00000f  000001
            // 30 days 7 days  1 day   1 hour  10 min  1 min   15 sec  1 sec
            let bitpacked := 0x278d00094890015180000f3c00025800003c00000f000001

            // Shift right by period * 24 bits & mask the least significant 24 bits.
            duration := and(shr(mul(resetPeriod, 24), bitpacked), 0xffffff)
        }
    }

    /**
     * @notice Internal pure function for computing an address's compact flag. The flag
     * is a 4-bit value that represents how "compact" the address of an allocator is. A
     * fully "compact" allocator address will have nine leading zero bytes, or eighteen
     * leading zero nibbles. To be considered even partially compact, the account must
     * have at least two leading zero bytes, or four leading zero nibbles. The full
     * scoring formula is therefore:
     *  - 0-3 leading zero nibbles: 0
     *  - 4-17 leading zero nibbles: number of leading zeros minus 3
     *  - 18+ leading zero nibbles: 15
     * @param allocator    The address to compute the flag for.
     * @return compactFlag The computed compact flag.
     */
    function toCompactFlag(address allocator) internal pure returns (uint8 compactFlag) {
        assembly ("memory-safe") {
            // Extract the uppermost 72 bits of the address.
            let x := shr(184, shl(96, allocator))

            // Propagate the highest set bit.
            x := or(x, shr(1, x))
            x := or(x, shr(2, x))
            x := or(x, shr(4, x))
            x := or(x, shr(8, x))
            x := or(x, shr(16, x))
            x := or(x, shr(32, x))
            x := or(x, shr(64, x))

            // Count set bits to derive most significant bit in the last byte.
            let y := sub(x, and(shr(1, x), 0x5555555555555555))
            y := add(and(y, 0x3333333333333333), and(shr(2, y), 0x3333333333333333))
            y := and(add(y, shr(4, y)), 0x0f0f0f0f0f0f0f0f)
            y := add(y, shr(8, y))
            y := add(y, shr(16, y))
            y := add(y, shr(32, y))

            // Look up final value in the sequence.
            compactFlag := and(shr(and(sub(72, and(y, 127)), not(3)), 0xfedcba9876543210000), 15)
        }
    }

    /**
     * @notice Internal pure function for extracting the allocator ID from a resource
     * lock ID. The allocator ID is a 92-bit value, with the first 4 bits representing
     * the compact flag and the last 88 bits matching the last 88 bits of the underlying
     * allocator, but is represented by a uint96 as solidity only supports uint values
     * for multiples of 8 bits.
     * @param id           The resource lock ID to extract from.
     * @return allocatorId The allocator ID (bits 160-251).
     */
    function toAllocatorId(uint256 id) internal pure returns (uint96 allocatorId) {
        assembly ("memory-safe") {
            // Extract bits 5-96.
            allocatorId := shr(164, shl(4, id))
        }
    }

    /**
     * @notice Internal pure function for computing an allocator's ID from their address.
     * Combines the compact flag (4 bits) with the last 88 bits of the address.
     * @param allocator    The address to compute the ID for.
     * @return allocatorId The computed allocator ID.
     */
    function toAllocatorId(address allocator) internal pure returns (uint96 allocatorId) {
        uint8 compactFlag = allocator.toCompactFlag();

        assembly ("memory-safe") {
            allocatorId := or(shl(88, compactFlag), shr(168, shl(168, allocator)))
        }
    }

    /**
     * @notice Internal pure function for extracting the allocator ID from a resource
     * lock tag. The allocator ID is a 92-bit value, with the first 4 bits representing
     * the compact flag and the last 88 bits matching the last 88 bits of the underlying
     * allocator, but is represented by a uint96 as solidity only supports uint values
     * for multiples of 8 bits.
     * @param lockTag      The resource lock tag to extract from.
     * @return allocatorId The allocator ID (bits 160-251).
     */
    function toAllocatorId(bytes12 lockTag) internal pure returns (uint96 allocatorId) {
        assembly ("memory-safe") {
            // Extract bits 5-96.
            allocatorId := shr(164, shl(4, lockTag))
        }
    }

    /**
     * @notice Internal view function for ensuring that the allocator ID from a resource
     * lock tag is registered to an allocator.
     * @param lockTag The resource lock tag to check allocator registration for.
     */
    function hasRegisteredAllocatorId(bytes12 lockTag) internal view {
        lockTag.toAllocatorId().mustHaveARegisteredAllocator();
    }
}

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

/**
 * @title ConsumerLib
 * @notice Library contract implementing logic for consuming bitpacked nonces scoped to
 * specific accounts and for querying for the state of those nonces. Note that only the
 * allocator nonce scope is currently in use in The Compact.
 */
library ConsumerLib {
    // Storage scope identifiers for nonce buckets.
    uint256 private constant _ALLOCATOR_NONCE_SCOPE = 0x03f37b1a;

    // Error thrown when attempting to consume an already-consumed nonce.
    error InvalidNonce(address account, uint256 nonce);

    /**
     * @notice Internal function for consuming a nonce in the allocator's scope.
     * @param nonce     The nonce to consume.
     * @param allocator The address of the allocator whose scope to consume the nonce in.
     */
    function consumeNonceAsAllocator(uint256 nonce, address allocator) internal {
        _consumeNonce(nonce, allocator, _ALLOCATOR_NONCE_SCOPE);
    }

    /**
     * @notice Internal view function for checking if a nonce has been consumed in the
     * allocator's scope.
     * @param nonceToCheck The nonce to check.
     * @param allocator    The address of the allocator whose scope to check.
     * @return consumed    Whether the nonce has been consumed.
     */
    function isConsumedByAllocator(uint256 nonceToCheck, address allocator) internal view returns (bool consumed) {
        return _isConsumedBy(nonceToCheck, allocator, _ALLOCATOR_NONCE_SCOPE);
    }

    /**
     * @notice Private function implementing nonce consumption logic. Uses the last byte
     * of the nonce to determine which bit to set in a 256-bit storage bucket unique to
     * the account and scope. Reverts if the nonce has already been consumed.
     * @param nonce   The nonce to consume.
     * @param account The address of the account whose scope to consume the nonce in.
     * @param scope   The scope identifier to consume the nonce in.
     */
    function _consumeNonce(uint256 nonce, address account, uint256 scope) private {
        // The last byte of the nonce is used to assign a bit in a 256-bit bucket;
        // specific nonces are consumed for each account and can only be used once.
        // NOTE: this function temporarily overwrites the free memory pointer, but
        // restores it before returning.
        assembly ("memory-safe") {
            // Store free memory pointer; its memory location will be overwritten.
            let freeMemoryPointer := mload(0x40)

            // derive the nonce bucket slot:
            // keccak256(_ALLOCATOR_NONCE_SCOPE ++ account ++ nonce[0:31])
            mstore(0x20, account)
            mstore(0x0c, scope)
            mstore(0x40, nonce)
            let bucketSlot := keccak256(0x28, 0x37)

            // Retrieve nonce bucket and check if nonce has been consumed.
            let bucketValue := sload(bucketSlot)
            let bit := shl(and(0xff, nonce), 1)
            if and(bit, bucketValue) {
                // `InvalidNonce(address,uint256)` with padding for `account`.
                mstore(0x0c, shl(96, 0xdbc205b1))
                revert(0x1c, 0x44)
            }

            // Invalidate the nonce by setting its bit.
            sstore(bucketSlot, or(bucketValue, bit))

            // Restore the free memory pointer.
            mstore(0x40, freeMemoryPointer)
        }
    }

    /**
     * @notice Private view function implementing nonce consumption checking logic.
     * Uses the last byte of the nonce to determine which bit to check in a 256-bit
     * storage bucket unique to the account and scope.
     * @param nonceToCheck The nonce to check.
     * @param account      The address of the account whose scope to check.
     * @param scope        The scope identifier to check.
     * @return consumed    Whether the nonce has been consumed.
     */
    function _isConsumedBy(uint256 nonceToCheck, address account, uint256 scope) private view returns (bool consumed) {
        assembly ("memory-safe") {
            // Store free memory pointer; its memory location will be overwritten.
            let freeMemoryPointer := mload(0x40)

            // derive the nonce bucket slot:
            // keccak256(_ALLOCATOR_NONCE_SCOPE ++ account ++ nonce[0:31])
            mstore(0x20, account)
            mstore(0x0c, scope)
            mstore(0x40, nonceToCheck)

            // Load the nonce bucket and check whether the target nonce bit is set.
            // 1. `sload(keccak256(0x28, 0x37))`      – load the 256-bit bucket.
            // 2. `and(0xff, nonceToCheck)`           – isolate the least-significant byte (bit index 0-255).
            // 3. `shl(index, 1)`                     – build a mask (1 << index).
            // 4. `and(mask, bucket)`                 – leave only the target bit.
            // 5. `gt(result, 0)`                     – cast to a clean boolean (avoids dirty bits).
            consumed := gt(and(shl(and(0xff, nonceToCheck), 1), sload(keccak256(0x28, 0x37))), 0)

            // Restore the free memory pointer.
            mstore(0x40, freeMemoryPointer)
        }
    }
}

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

/**
 * @title DomainLib
 * @notice Library contract implementing logic for deriving domain hashes.
 */
library DomainLib {
    /// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`.
    bytes32 internal constant _DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;

    /// @dev `keccak256(bytes("The Compact"))`.
    bytes32 internal constant _NAME_HASH = 0x5e6f7b4e1ac3d625bac418bc955510b3e054cb6cc23cc27885107f080180b292;

    /// @dev `keccak256("1")`.
    bytes32 internal constant _VERSION_HASH = 0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6;

    /**
     * @notice Internal view function that returns the current domain separator, deriving a new one
     * if the chain ID has changed from the initial chain ID.
     * @param initialDomainSeparator The domain separator derived at deployment time.
     * @param initialChainId         The chain ID at the time of deployment.
     * @return domainSeparator       The current domain separator.
     */
    function toLatest(bytes32 initialDomainSeparator, uint256 initialChainId)
        internal
        view
        returns (bytes32 domainSeparator)
    {
        // Set the initial domain separator as the default domain separator.
        domainSeparator = initialDomainSeparator;

        assembly ("memory-safe") {
            // Derive domain separator again if initial chain ID differs from current one.
            if xor(chainid(), initialChainId) {
                // Retrieve the free memory pointer.
                let m := mload(0x40)

                // Prepare domain data: EIP-712 typehash, name hash, version hash, chain ID, & verifying contract.
                mstore(m, _DOMAIN_TYPEHASH)
                mstore(add(m, 0x20), _NAME_HASH)
                mstore(add(m, 0x40), _VERSION_HASH)
                mstore(add(m, 0x60), chainid())
                mstore(add(m, 0x80), address())

                // Derive the domain separator.
                domainSeparator := keccak256(m, 0xa0)
            }
        }
    }

    /**
     * @notice Internal view function that derives a domain separator for a specific chain ID.
     * Used for notarizing multichain claims with segments that will be executed on a different chain.
     * @param notarizedChainId          The chain ID to derive the domain separator for.
     * @return notarizedDomainSeparator The domain separator for the specified chain ID.
     */
    function toNotarizedDomainSeparator(uint256 notarizedChainId)
        internal
        view
        returns (bytes32 notarizedDomainSeparator)
    {
        assembly ("memory-safe") {
            // Retrieve the free memory pointer.
            let m := mload(0x40)

            // Prepare domain data: EIP-712 typehash, name hash, version hash, notarizing chain ID, and verifying contract.
            mstore(m, _DOMAIN_TYPEHASH)
            mstore(add(m, 0x20), _NAME_HASH)
            mstore(add(m, 0x40), _VERSION_HASH)
            mstore(add(m, 0x60), notarizedChainId)
            mstore(add(m, 0x80), address())

            // Derive the domain separator.
            notarizedDomainSeparator := keccak256(m, 0xa0)
        }
    }

    /**
     * @notice Internal pure function that combines a message hash with a domain separator
     * to create a domain-specific hash according to EIP-712.
     * @param messageHash     The EIP-712 hash of the message data.
     * @param domainSeparator The domain separator to combine with the message hash.
     * @return domainHash     The domain-specific hash.
     */
    function withDomain(bytes32 messageHash, bytes32 domainSeparator) internal pure returns (bytes32 domainHash) {
        assembly ("memory-safe") {
            // Retrieve and cache the free memory pointer.
            let m := mload(0x40)

            // Prepare the 712 prefix.
            mstore(0, 0x1901)

            // Prepare the domain separator.
            mstore(0x20, domainSeparator)

            // Prepare the message hash and compute the domain hash.
            mstore(0x40, messageHash)
            domainHash := keccak256(0x1e, 0x42)

            // Restore the free memory pointer.
            mstore(0x40, m)
        }
    }
}

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

import { IdLib } from "./IdLib.sol";
import { ResetPeriod } from "../types/ResetPeriod.sol";
import { EmissaryConfig, EmissaryStatus } from "../types/EmissaryStatus.sol";
import { EfficiencyLib } from "./EfficiencyLib.sol";

/**
 * @title EmissaryLib
 * @notice This library manages the assignment and verification of emissaries for sponsors
 * within the system. An emissary is an address that can verify claims on behalf of a sponsor.
 * The library enforces security constraints and scheduling rules to ensure proper delegation.
 *
 * @dev The library uses a storage-efficient design with a single storage slot for all emissary
 * configurations, using mappings to organize data by sponsor and allocator ID. This allows for
 * efficient storage and access while maintaining data isolation between different sponsors.
 *
 * Key Components:
 * - EmissarySlot: Storage structure that maps sponsors to their allocator ID configurations
 * - EmissaryConfig: Configuration data for each emissary assignment, including reset periods
 * - Assignment scheduling: Enforces cooldown periods between assignments to prevent abuse
 * - Verification: Delegates claim verification to the assigned emissary contract
 *
 * Security Features:
 * - Timelock mechanism for reassignment to prevent rapid succession of emissaries
 * - Clear state management with Disabled/Enabled/Scheduled statuses
 * - Storage cleanup when emissaries are removed
 */
library EmissaryLib {
    using IdLib for bytes12;
    using IdLib for uint256;
    using IdLib for ResetPeriod;
    using EfficiencyLib for bool;

    // Sentinel value of type(uint96).max representing an emissary without a scheduled assignment.
    uint96 private constant NOT_SCHEDULED = 0xffffffffffffffffffffffff;

    // Scope for storage slots containing emissary configurations.
    // bytes4(keccak256("_EMISSARY_SCOPE")).
    uint256 private constant _EMISSARY_SCOPE = 0x2d5c707e;

    // bytes4(keccak256("verifyClaim(address,bytes32,bytes32,bytes,bytes12)")).
    uint32 private constant _VERIFY_CLAIM_SELECTOR = 0xf699ba1c;

    // keccak256("EmissaryAssigned(address,bytes12,address)").
    uint256 private constant _EMISSARY_ASSIGNED_EVENT_SIGNATURE =
        0x92de0e90f030663724bafa9b7a9ba2643e3f4ced55f1cfee8b01e2682aeb45fd;

    // keccak256("EmissaryAssignmentScheduled(address,bytes12,uint256)").
    uint256 private constant _EMISSARY_ASSIGNMENT_SCHEDULED_EVENT_SIGNATURE =
        0x16c05a1aea0a2659b53f72fda6b47106e4aa07338b16993a01ece024df9d8cc4;

    /**
     * @notice Internal function to assign or remove an emissary for a specific sponsor and
     * lock tag. This ensures that the assignment process adheres to the scheduling rules
     * and prevents invalid or premature assignments. It also clears the configuration
     * when removing an emissary to keep storage clean and avoid stale data.
     * @param lockTag     The lockTag of the emissary.
     * @param newEmissary The address of the new emissary, or address(0) to remove.
     */
    function assignEmissary(bytes12 lockTag, address newEmissary) internal {
        EmissaryConfig storage config = _getEmissaryConfig(msg.sender, lockTag);
        uint256 assignableAt = config.assignableAt;
        address currentEmissary = config.emissary;

        // Ensure assignment has been properly scheduled if an emissary is currently set.
        // Note that assignment can occur immediately if no emissary is set. Emissaries that
        // do not have a scheduled assignment will have an assignableAt of type(uint96).max
        // which will prohibit assignment as the timestamp cannot exceed that value.
        assembly ("memory-safe") {
            if and(iszero(iszero(currentEmissary)), gt(assignableAt, timestamp())) {
                // Revert EmissaryAssignmentUnavailable(assignableAt);
                mstore(0, 0x174f0776)
                mstore(0x20, assignableAt)
                revert(0x1c, 0x24)
            }
        }

        // If new Emissary is address(0), that means that the sponsor wants to remove their emissary.
        // In that event, wipe all related storage.
        if (newEmissary == address(0)) {
            // If the new emissary is address(0), this means the emissary should be removed.
            // Clear all related storage fields to maintain a clean state and avoid stale data.
            delete config.emissary;
            delete config.assignableAt;
        }
        // Otherwise, set the provided newEmissary.
        else {
            config.emissary = newEmissary;
            config.assignableAt = NOT_SCHEDULED;
        }

        assembly ("memory-safe") {
            // Emit EmissaryAssigned(msg.sender, lockTag, newEmissary) event.
            log4(0, 0, _EMISSARY_ASSIGNED_EVENT_SIGNATURE, caller(), lockTag, newEmissary)
        }
    }

    /**
     * @notice Internal function to schedule a future assignment for an emissary.
     * The scheduling mechanism ensures that emissaries cannot be reassigned arbitrarily,
     * enforcing a reset period that must elapse before a new assignment is possible.
     * This prevents abuse of the system by requiring a cooldown period between assignments.
     * @param lockTag       The lock tag for the assignment.
     * @return assignableAt The timestamp when the assignment becomes available.
     */
    function scheduleEmissaryAssignment(bytes12 lockTag) internal returns (uint256 assignableAt) {
        // Get the current emissary config from storage.
        EmissaryConfig storage emissaryConfig = _getEmissaryConfig(msg.sender, lockTag);

        unchecked {
            // Extract three-bit resetPeriod from lockTag, convert to seconds, & add to current time.
            assignableAt = block.timestamp + lockTag.toResetPeriod().toSeconds();
        }

        // Write the resultant value to storage. Note that assignableAt is expected to remain in uint96
        // range, as block timestamps will not reach upper uint96 range in realistic timeframes and
        // ResetPeriod is capped at thirty days.
        emissaryConfig.assignableAt = uint96(assignableAt);

        assembly ("memory-safe") {
            // Emit EmissaryAssignmentScheduled(msg.sender, lockTag, assignableAt) event.
            mstore(0, assignableAt)
            log3(0, 0x20, _EMISSARY_ASSIGNMENT_SCHEDULED_EVENT_SIGNATURE, caller(), lockTag)
        }
    }

    /**
     * @notice Internal view function to verify a claim using the assigned emissary.
     * This function delegates the verification logic to the emissary contract,
     * ensuring that the verification process is modular and can be updated independently.
     * If no emissary is assigned, the verification fails, enforcing the requirement
     * for an active emissary to validate claims.
     * @param digest    The digest of the claim on the notarized chain.
     * @param claimHash The hash of the claim to verify.
     * @param sponsor   The address of the sponsor.
     * @param lockTag   The lock tag for the claim.
     * @param signature The signature to verify.
     */
    function verifyWithEmissary(
        bytes32 digest,
        bytes32 claimHash,
        address sponsor,
        bytes12 lockTag,
        bytes calldata signature
    ) internal view {
        // Retrieve the emissary for the sponsor and lock tag from storage.
        address emissary = _getEmissaryConfig(sponsor, lockTag).emissary;

        // Revert if no emissary is assigned.
        assembly ("memory-safe") {
            if iszero(emissary) {
                // revert InvalidSignature();
                mstore(0, 0x8baa579f)
                revert(0x1c, 0x04)
            }
        }

        // Delegate the verification process to the assigned emissary contract.
        _callVerifyClaim(emissary, sponsor, digest, claimHash, signature, lockTag);
    }

    /**
     * @notice Internal view function to retrieve the current status of an emissary for a given
     * sponsor and lock tag. The status provides insight into whether the emissary is active,
     * disabled, or scheduled for reassignment. This provides visibility into the state of the
     * emissary system without needing to interpret raw configuration data.
     * @param sponsor          The address of the sponsor.
     * @param lockTag          The lock tag for the emissary.
     * @return status          The current status of the emissary.
     * @return assignableAt    The timestamp when the emissary can be reassigned.
     * @return currentEmissary The address of the currently assigned emissary.
     */
    function getEmissaryStatus(address sponsor, bytes12 lockTag)
        internal
        view
        returns (EmissaryStatus status, uint256 assignableAt, address currentEmissary)
    {
        EmissaryConfig storage emissaryConfig = _getEmissaryConfig(sponsor, lockTag);
        assignableAt = emissaryConfig.assignableAt;
        currentEmissary = emissaryConfig.emissary;

        // Determine the emissary's status based on its current state:
        // - If there is no current emissary, the status is Disabled and assignableAt must be zero.
        // - If assignableAt is NOT_SCHEDULED, the emissary is Enabled and active.
        // - If assignableAt is set to a future timestamp, the emissary is Scheduled for reassignment.
        if (currentEmissary == address(0)) {
            status = EmissaryStatus.Disabled;
        } else if (assignableAt == NOT_SCHEDULED) {
            status = EmissaryStatus.Enabled;
        } else {
            status = EmissaryStatus.Scheduled;
        }
    }

    /**
     * @notice Internal pure function to extract and verify that all IDs in a given idsAndAmounts array have
     * the same lock tag.
     * @param idsAndAmounts Array of [id, amount] pairs.
     * @return lockTag      The common lock tag across all IDs.
     */
    function extractSameLockTag(uint256[2][] memory idsAndAmounts) internal pure returns (bytes12 lockTag) {
        // Store the first lockTag for the first id. Note that idsAndAmounts is known to be non-zero
        // length at this point, as it gets checked in _buildIdsAndAmountsWithConsistentAllocatorIdCheck in ComponentLib.
        lockTag = idsAndAmounts[0][0].toLockTag();

        // Initialize an error buffer.
        uint256 errorBuffer;

        // Retrieve the length of the array.
        uint256 idsAndAmountsLength = idsAndAmounts.length;

        // Iterate over remaining array elements.
        for (uint256 i = 1; i < idsAndAmountsLength; ++i) {
            // Set the error buffer if lockTag does not match initial lockTag.
            errorBuffer |= (idsAndAmounts[i][0].toLockTag() != lockTag).asUint256();
        }

        // Ensure that no lockTag values differ.
        assembly ("memory-safe") {
            if errorBuffer {
                // Revert InvalidLockTag();
                mstore(0, 0xbbfc3c51)
                revert(0x1c, 0x04)
            }
        }
    }

    /**
     * @notice Private view function to perform a low-level verifyClaim staticcall to an
     * emissary, ensuring that the expected magic value (verifyClaim function selector) is
     * returned. Reverts if the magic value is not returned successfully.
     * @param emissary  The emissary to perform the call to.
     * @param sponsor   The address of the sponsor.
     * @param digest    The digest of the claim to verify.
     * @param claimHash The hash of the claim to verify.
     * @param signature The signature to verify.
     * @param lockTag   The lock tag for the claim.
     */
    function _callVerifyClaim(
        address emissary,
        address sponsor,
        bytes32 digest,
        bytes32 claimHash,
        bytes calldata signature,
        bytes12 lockTag
    ) private view {
        assembly ("memory-safe") {
            // Retrieve the free memory pointer; memory will be left dirtied.
            let m := mload(0x40)

            // Derive offset to start of data for the call from memory pointer.
            let dataStart := add(m, 0x1c)

            // Prepare fixed-location components of calldata.
            mstore(add(m, 0x20), sponsor)
            mstore(add(m, 0x0c), 0) // Clear any dirty upper bits on sponsor.
            mstore(m, _VERIFY_CLAIM_SELECTOR)
            mstore(add(m, 0x40), digest)
            mstore(add(m, 0x60), claimHash)
            mstore(add(m, 0x80), 0xa0)
            mstore(add(m, 0xa0), lockTag)
            mstore(add(m, 0xac), 0) // clear any dirty lower bits on lock tag.
            mstore(add(m, 0xc0), signature.length)
            calldatacopy(add(m, 0xe0), signature.offset, signature.length)

            // Ensure initial scratch space is cleared as an added precaution.
            mstore(0, 0)

            // Perform a staticcall to emissary and write response to scratch space.
            let success := staticcall(gas(), emissary, dataStart, add(0xc4, signature.length), 0, 0x20)

            // Revert if the required magic value was not received back.
            if iszero(eq(mload(0), shl(0xe0, _VERIFY_CLAIM_SELECTOR))) {
                // Bubble up if the call failed and there's data. Note that remaining gas is not evaluated before
                // copying the returndata buffer into memory. Out-of-gas errors can be triggered via revert bombing.
                if iszero(or(success, iszero(returndatasize()))) {
                    returndatacopy(0, 0, returndatasize())
                    revert(0, returndatasize())
                }

                // revert InvalidSignature();
                mstore(0, 0x8baa579f)
                revert(0x1c, 0x04)
            }
        }
    }

    /**
     * @notice Private pure function to retrieve the configuration for a given emissary.
     * This ensures that emissary-specific settings (like reset period and assignment time)
     * are stored and retrieved in a consistent and isolated manner to prevent conflicts.
     * The function uses a combination of sponsor address, lockTag, and a scope constant
     * to compute a unique storage slot for the configuration.
     * @param sponsor The address of the sponsor that the emissary is associated with.
     * @param lockTag The lock tag to which the emissary assignment is associated.
     * @return config The configuration for the emissary in storage.
     */
    function _getEmissaryConfig(address sponsor, bytes12 lockTag)
        private
        pure
        returns (EmissaryConfig storage config)
    {
        // Pack and hash scope, sponsor, and lock tag to derive emissary config storage slot.
        assembly ("memory-safe") {
            // Start by writing the sponsor address to scratch space so that the 20 bytes of
            // address data are placed at memory location 0x20. The first 12 bytes of the
            // variable for the sponsor are unused and overwritten by the subsequent write.
            mstore(0x14, sponsor)

            // Next, write the emissary scope value to scratch space so that the 4 bytes of
            // scope data are placed at the memory location 0x1c. The first 28 bytes of the
            // variable for the emissary scope are unused and will be omitted from the slot
            // derivation; a right-aligned value is preferred over a left-aligned one like
            // bytes4 to reduce code size requirements without needing bitshift operations.
            mstore(0, _EMISSARY_SCOPE)

            // Then, write the lock tag value to scratch space so that the 12 bytes of
            // lock tag data are placed at memory location 0x34. This data is left-aligned
            // and so it can be placed directly at the intended memory location, and the
            // final 20 bytes will not be included in the slot derivation. Note that these
            // unused least-significant bits will overflow into the free memory pointer and
            // will need to be cleared in a subsequent step if there are any dirty lower bits
            // on the lockTag value. Since a valid free memory pointer can never grow to a
            // value that would require the 20 most-significant bytes in the pointer (as this
            // would certainly exhaust memory long before they were needed), these bytes can
            // safely be used as long as they are cleared before accessing the pointer again.
            mstore(0x34, lockTag)

            // Compute storage slot from packed data.
            // Start at offset 0x1c (28 bytes) and hash 0x24 (36 bytes) of data in total:
            // - _EMISSARY_SCOPE (4 bytes from at 0x1c to 0x20)
            // - Sponsor address (20 bytes from 0x20 to 0x34)
            // - Lock tag (12 bytes from 0x34 to 0x40)
            config.slot := keccak256(0x1c, 0x24)

            // Finally, wipe the leftmost 20 bytes of the free memory pointer that may have
            // been set when writing the lock tag (assuming dirty lower bits were present).
            mstore(0x34, 0)
        }
    }
}

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

/**
 * @title RegistrationLib
 * @notice Library contract implementing logic for registering compact claim hashes
 * and typehashes and querying for whether given claim hashes and typehashes have
 * been registered.
 */
library RegistrationLib {
    using RegistrationLib for address;

    // keccak256(bytes("CompactRegistered(address,bytes32,bytes32)")).
    uint256 private constant _COMPACT_REGISTERED_SIGNATURE =
        0x52dd3aeaf9d70bfcfdd63526e155ba1eea436e7851acf5c950299321c671b927;

    // Storage scope for active registrations:
    // slot: keccak256(_ACTIVE_REGISTRATIONS_SCOPE ++ sponsor ++ claimHash ++ typehash) => expires.
    uint256 private constant _ACTIVE_REGISTRATIONS_SCOPE = 0x68a30dd0;

    /**
     * @notice Internal function for registering a claim hash.
     * @param sponsor   The account registering the claim hash.
     * @param claimHash A bytes32 hash derived from the details of the compact.
     * @param typehash  The EIP-712 typehash associated with the claim hash.
     */
    function registerCompact(address sponsor, bytes32 claimHash, bytes32 typehash) internal {
        uint256 registrationSlot = sponsor.deriveRegistrationSlot(claimHash, typehash);
        assembly ("memory-safe") {
            // Store 1 (true) in active registration storage slot.
            sstore(registrationSlot, 1)

            // Emit the CompactRegistered event:
            //  - topic1: CompactRegistered event signature
            //  - topic2: sponsor address (sanitized)
            //  - data: [claimHash, typehash]
            mstore(0, claimHash)
            mstore(0x20, typehash)
            log2(0, 0x40, _COMPACT_REGISTERED_SIGNATURE, shr(0x60, shl(0x60, sponsor)))
        }
    }

    /**
     * @notice Internal function for registering multiple claim hashes in a single call.
     * @param claimHashesAndTypehashes Array of [claimHash, typehash] pairs for registration.
     * @return                         Whether all claim hashes were successfully registered.
     */
    function registerBatchAsCaller(bytes32[2][] calldata claimHashesAndTypehashes) internal returns (bool) {
        // Retrieve the total number of claim hashes and typehashes to register.
        uint256 totalClaimHashes = claimHashesAndTypehashes.length;

        // Iterate over each pair of claim hashes and typehashes.
        for (uint256 i = 0; i < totalClaimHashes; ++i) {
            // Retrieve the claim hash and typehash from calldata.
            bytes32[2] calldata claimHashAndTypehash = claimHashesAndTypehashes[i];

            // Register the compact as the caller.
            msg.sender.registerCompact(claimHashAndTypehash[0], claimHashAndTypehash[1]);
        }

        return true;
    }

    /**
     * @notice Internal view function for retrieving the timestamp of a registration.
     * @param sponsor   The account that registered the claim hash.
     * @param claimHash A bytes32 hash derived from the details of the compact.
     * @param typehash  The EIP-712 typehash associated with the claim hash.
     * @return registered Whether the compact has been registered.
     */
    function isRegistered(address sponsor, bytes32 claimHash, bytes32 typehash)
        internal
        view
        returns (bool registered)
    {
        uint256 registrationSlot = sponsor.deriveRegistrationSlot(claimHash, typehash);
        assembly ("memory-safe") {
            // Load registration storage slot to get registration status.
            registered := sload(registrationSlot)
        }
    }

    /**
     * @notice Internal function for consuming (clearing) a registration.
     * @param sponsor   The account that registered the claim hash.
     * @param claimHash A bytes32 hash derived from the details of the compact.
     * @param typehash  The EIP-712 typehash associated with the claim hash.
     */
    function consumeRegistrationIfRegistered(address sponsor, bytes32 claimHash, bytes32 typehash)
        internal
        returns (bool consumed)
    {
        uint256 registrationSlot = sponsor.deriveRegistrationSlot(claimHash, typehash);
        assembly ("memory-safe") {
            consumed := sload(registrationSlot)
            if consumed { sstore(registrationSlot, 0) }
        }
    }

    /**
     * @notice Internal function for deriving the registration storage slot for a given claim hash and typehash.
     * @param sponsor   The account that registered the claim hash.
     * @param claimHash A bytes32 hash derived from the details of the compact.
     * @param typehash  The EIP-712 typehash associated with the claim hash.
     * @return registrationSlot The storage slot for the registration.
     */
    function deriveRegistrationSlot(address sponsor, bytes32 claimHash, bytes32 typehash)
        internal
        pure
        returns (uint256 registrationSlot)
    {
        assembly ("memory-safe") {
            // Retrieve the current free memory pointer.
            let m := mload(0x40)

            // Pack data for deriving active registration storage slot.
            mstore(add(m, 0x14), sponsor)
            mstore(m, _ACTIVE_REGISTRATIONS_SCOPE)
            mstore(add(m, 0x34), claimHash)
            mstore(add(m, 0x54), typehash)

            // Derive active registration storage slot.
            registrationSlot := keccak256(add(m, 0x1c), 0x58)
        }
    }
}

File 29 of 41 : ResetPeriod.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

enum ResetPeriod {
    OneSecond,
    FifteenSeconds,
    OneMinute,
    TenMinutes,
    OneHourAndFiveMinutes,
    OneDay,
    SevenDaysAndOneHour,
    ThirtyDays
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

/**
 * @notice Minimal interface for interacting with Arbitrum system contracts
 * @custom:security-contact [email protected]
 */
interface IArbSys {
    /**
     * @notice Get Arbitrum block number (distinct from L1 block number; Arbitrum genesis block has block number 0)
     * @return block number as int
     */
    function arbBlockNumber() external view returns (uint256);
}

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

import { Component } from "./Components.sol";

struct AllocatedTransfer {
    bytes allocatorData; // Authorization from the allocator.
    uint256 nonce; // A parameter to enforce replay protection, scoped to allocator.
    uint256 expires; // The time at which the transfer or withdrawal expires.
    uint256 id; // The token ID of the ERC6909 token to transfer or withdraw.
    Component[] recipients; // The recipients and amounts of each transfer.
}

struct Claim {
    bytes allocatorData; // Authorization from the allocator.
    bytes sponsorSignature; // Authorization from the sponsor.
    address sponsor; // The account to source the tokens from.
    uint256 nonce; // A parameter to enforce replay protection, scoped to allocator.
    uint256 expires; // The time at which the claim expires.
    bytes32 witness; // Hash of the witness data.
    string witnessTypestring; // Witness typestring appended to existing typestring.
    uint256 id; // The token ID of the ERC6909 token to allocate.
    uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens.
    Component[] claimants; // The claim recipients and amounts; specified by the arbiter.
}

library ClaimsLib {
    /**
     * @notice Returns the raw calldata pointer to the claim.
     * @param claim The claim to get the raw pointer of.
     * @return rawClaimPtr The raw pointer to the claim.
     */
    function asRawPtr(Claim calldata claim) internal pure returns (uint256 rawClaimPtr) {
        assembly {
            rawClaimPtr := claim
        }
    }
}

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

import { Component } from "./Components.sol";

struct MultichainClaim {
    bytes allocatorData; // Authorization from the allocator.
    bytes sponsorSignature; // Authorization from the sponsor.
    address sponsor; // The account to source the tokens from.
    uint256 nonce; // A parameter to enforce replay protection, scoped to allocator.
    uint256 expires; // The time at which the claim expires.
    bytes32 witness; // Hash of the witness data.
    string witnessTypestring; // Witness typestring appended to existing typestring.
    uint256 id; // The token ID of the ERC6909 token to allocate.
    uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens.
    Component[] claimants; // The claim recipients and amounts; specified by the arbiter.
    bytes32[] additionalChains; // The element hashes from additional chains.
}

struct ExogenousMultichainClaim {
    bytes allocatorData; // Authorization from the allocator.
    bytes sponsorSignature; // Authorization from the sponsor.
    address sponsor; // The account to source the tokens from.
    uint256 nonce; // A parameter to enforce replay protection, scoped to allocator.
    uint256 expires; // The time at which the claim expires.
    bytes32 witness; // Hash of the witness data.
    string witnessTypestring; // Witness typestring appended to existing typestring.
    uint256 id; // The token ID of the ERC6909 token to allocate.
    uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens.
    Component[] claimants; // The claim recipients and amounts; specified by the arbiter.
    bytes32[] additionalChains; // The element hashes from additional chains.
    uint256 chainIndex; // The index after which to insert the current element hash.
    uint256 notarizedChainId; // The chain id used to sign the multichain claim.
}

library MultichainClaimsLib {
    /**
     * @notice Returns the raw calldata pointer to the multichain claim.
     * @param claim The multichain claim to get the raw pointer of.
     * @return rawClaimPtr The raw pointer to the multichain claim.
     */
    function asRawPtr(MultichainClaim calldata claim) internal pure returns (uint256 rawClaimPtr) {
        assembly {
            rawClaimPtr := claim
        }
    }

    /**
     * @notice Returns the raw calldata pointer to the exogenous multichain claim.
     * @param claim The exogenous multichain claim to get the raw pointer of.
     * @return rawClaimPtr The raw pointer to the exogenous multichain claim.
     */
    function asRawPtr(ExogenousMultichainClaim calldata claim) internal pure returns (uint256 rawClaimPtr) {
        assembly {
            rawClaimPtr := claim
        }
    }
}

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

import { BatchClaimComponent } from "./Components.sol";

struct BatchMultichainClaim {
    bytes allocatorData; // Authorization from the allocator.
    bytes sponsorSignature; // Authorization from the sponsor.
    address sponsor; // The account to source the tokens from.
    uint256 nonce; // A parameter to enforce replay protection, scoped to allocator.
    uint256 expires; // The time at which the claim expires.
    bytes32 witness; // Hash of the witness data.
    string witnessTypestring; // Witness typestring appended to existing typestring.
    BatchClaimComponent[] claims; // The claim token IDs, recipients and amounts.
    bytes32[] additionalChains; // The element hashes from additional chains.
}

struct ExogenousBatchMultichainClaim {
    bytes allocatorData; // Authorization from the allocator.
    bytes sponsorSignature; // Authorization from the sponsor.
    address sponsor; // The account to source the tokens from.
    uint256 nonce; // A parameter to enforce replay protection, scoped to allocator.
    uint256 expires; // The time at which the claim expires.
    bytes32 witness; // Hash of the witness data.
    string witnessTypestring; // Witness typestring appended to existing typestring.
    BatchClaimComponent[] claims; // The claim token IDs, recipients and amounts.
    bytes32[] additionalChains; // The element hashes from additional chains.
    uint256 chainIndex; // The index after which to insert the current element hash.
    uint256 notarizedChainId; // The chain id used to sign the multichain claim.
}

library BatchMultichainClaimsLib {
    /**
     * @notice Returns the raw calldata pointer to the batch multichain claim.
     * @param claim The batch multichain claim to get the raw pointer of.
     * @return rawClaimPtr The raw pointer to the batch multichain claim.
     */
    function asRawPtr(BatchMultichainClaim calldata claim) internal pure returns (uint256 rawClaimPtr) {
        assembly {
            rawClaimPtr := claim
        }
    }

    /**
     * @notice Returns the raw calldata pointer to the exogenous batch multichain claim.
     * @param claim The exogenous batch multichain claim to get the raw pointer of.
     * @return rawClaimPtr The raw pointer to the exogenous batch multichain claim.
     */
    function asRawPtr(ExogenousBatchMultichainClaim calldata claim) internal pure returns (uint256 rawClaimPtr) {
        assembly {
            rawClaimPtr := claim
        }
    }
}

File 34 of 41 : ForcedWithdrawalStatus.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

enum ForcedWithdrawalStatus {
    Disabled, // Not pending or enabled for forced withdrawal
    Pending, // Not yet available, but initiated
    Enabled // Available for forced withdrawal on demand

}

File 35 of 41 : EmissaryStatus.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

enum EmissaryStatus {
    Disabled, // Not pending or enabled for forced withdrawal
    Scheduled, // Available but scheduled
    Enabled // Available for forced withdrawal on demand

}

struct EmissaryConfig {
    // 20 bytes
    address emissary; // address of the sponsor's emissary
    // 12 bytes
    uint96 assignableAt; // timestamp after which an emissary can be re-assigned
}

File 36 of 41 : CompactCategory.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

enum CompactCategory {
    Compact,
    BatchCompact,
    MultichainCompact
}

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

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

/// @title SignatureTransfer
/// @notice Handles ERC20 token transfers through signature based actions
/// @dev Requires user's token approval on the Permit2 contract
interface ISignatureTransfer is IEIP712 {
    /// @notice Thrown when the requested amount for a transfer is larger than the permissioned amount
    /// @param maxAmount The maximum amount a spender can request to transfer
    error InvalidAmount(uint256 maxAmount);

    /// @notice Thrown when the number of tokens permissioned to a spender does not match the number of tokens being transferred
    /// @dev If the spender does not need to transfer the number of tokens permitted, the spender can request amount 0 to be transferred
    error LengthMismatch();

    /// @notice Emits an event when the owner successfully invalidates an unordered nonce.
    event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask);

    /// @notice The token and amount details for a transfer signed in the permit transfer signature
    struct TokenPermissions {
        // ERC20 token address
        address token;
        // the maximum amount that can be spent
        uint256 amount;
    }

    /// @notice The signed permit message for a single token transfer
    struct PermitTransferFrom {
        TokenPermissions permitted;
        // a unique value for every token owner's signature to prevent signature replays
        uint256 nonce;
        // deadline on the permit signature
        uint256 deadline;
    }

    /// @notice Specifies the recipient address and amount for batched transfers.
    /// @dev Recipients and amounts correspond to the index of the signed token permissions array.
    /// @dev Reverts if the requested amount is greater than the permitted signed amount.
    struct SignatureTransferDetails {
        // recipient address
        address to;
        // spender requested amount
        uint256 requestedAmount;
    }

    /// @notice Used to reconstruct the signed permit message for multiple token transfers
    /// @dev Do not need to pass in spender address as it is required that it is msg.sender
    /// @dev Note that a user still signs over a spender address
    struct PermitBatchTransferFrom {
        // the tokens and corresponding amounts permitted for a transfer
        TokenPermissions[] permitted;
        // a unique value for every token owner's signature to prevent signature replays
        uint256 nonce;
        // deadline on the permit signature
        uint256 deadline;
    }

    /// @notice A map from token owner address and a caller specified word index to a bitmap. Used to set bits in the bitmap to prevent against signature replay protection
    /// @dev Uses unordered nonces so that permit messages do not need to be spent in a certain order
    /// @dev The mapping is indexed first by the token owner, then by an index specified in the nonce
    /// @dev It returns a uint256 bitmap
    /// @dev The index, or wordPosition is capped at type(uint248).max
    function nonceBitmap(address, uint256) external view returns (uint256);

    /// @notice Transfers a token using a signed permit message
    /// @dev Reverts if the requested amount is greater than the permitted signed amount
    /// @param permit The permit data signed over by the owner
    /// @param owner The owner of the tokens to transfer
    /// @param transferDetails The spender's requested transfer details for the permitted token
    /// @param signature The signature to verify
    function permitTransferFrom(
        PermitTransferFrom memory permit,
        SignatureTransferDetails calldata transferDetails,
        address owner,
        bytes calldata signature
    ) external;

    /// @notice Transfers a token using a signed permit message
    /// @notice Includes extra data provided by the caller to verify signature over
    /// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition
    /// @dev Reverts if the requested amount is greater than the permitted signed amount
    /// @param permit The permit data signed over by the owner
    /// @param owner The owner of the tokens to transfer
    /// @param transferDetails The spender's requested transfer details for the permitted token
    /// @param witness Extra data to include when checking the user signature
    /// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash
    /// @param signature The signature to verify
    function permitWitnessTransferFrom(
        PermitTransferFrom memory permit,
        SignatureTransferDetails calldata transferDetails,
        address owner,
        bytes32 witness,
        string calldata witnessTypeString,
        bytes calldata signature
    ) external;

    /// @notice Transfers multiple tokens using a signed permit message
    /// @param permit The permit data signed over by the owner
    /// @param owner The owner of the tokens to transfer
    /// @param transferDetails Specifies the recipient and requested amount for the token transfer
    /// @param signature The signature to verify
    function permitTransferFrom(
        PermitBatchTransferFrom memory permit,
        SignatureTransferDetails[] calldata transferDetails,
        address owner,
        bytes calldata signature
    ) external;

    /// @notice Transfers multiple tokens using a signed permit message
    /// @dev The witness type string must follow EIP712 ordering of nested structs and must include the TokenPermissions type definition
    /// @notice Includes extra data provided by the caller to verify signature over
    /// @param permit The permit data signed over by the owner
    /// @param owner The owner of the tokens to transfer
    /// @param transferDetails Specifies the recipient and requested amount for the token transfer
    /// @param witness Extra data to include when checking the user signature
    /// @param witnessTypeString The EIP-712 type definition for remaining string stub of the typehash
    /// @param signature The signature to verify
    function permitWitnessTransferFrom(
        PermitBatchTransferFrom memory permit,
        SignatureTransferDetails[] calldata transferDetails,
        address owner,
        bytes32 witness,
        string calldata witnessTypeString,
        bytes calldata signature
    ) external;

    /// @notice Invalidates the bits specified in mask for the bitmap at the word position
    /// @dev The wordPos is maxed at type(uint248).max
    /// @param wordPos A number to index the nonceBitmap at
    /// @param mask A bitmap masked against msg.sender's current bitmap at the word position
    function invalidateUnorderedNonces(uint256 wordPos, uint256 mask) external;
}

File 38 of 41 : DepositDetails.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;

struct DepositDetails {
    uint256 nonce;
    uint256 deadline;
    bytes12 lockTag;
}

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

interface IAllocator {
    /**
     * @notice Called on standard transfers to validate the transfer.
     * @param operator The address performing the transfer.
     * @param from     The address tokens are being transferred from.
     * @param to       The address tokens are being transferred to.
     * @param id       The ERC6909 token identifier being transferred.
     * @param amount   The amount of tokens being transferred.
     * @return         Must return this function selector (0x1a808f91).
     */
    function attest(address operator, address from, address to, uint256 id, uint256 amount) external returns (bytes4);

    /**
     * @notice Authorize a claim. Called from The Compact as part of claim processing.
     * @param claimHash      The message hash representing the claim.
     * @param arbiter        The account tasked with verifying and submitting the claim.
     * @param sponsor        The account to source the tokens from.
     * @param nonce          A parameter to enforce replay protection, scoped to allocator.
     * @param expires        The time at which the claim expires.
     * @param idsAndAmounts  The allocated token IDs and amounts.
     * @param allocatorData  Arbitrary data provided by the arbiter.
     * @return               Must return the function selector (0x7bb023f7).
     */
    function authorizeClaim(
        bytes32 claimHash,
        address arbiter,
        address sponsor,
        uint256 nonce,
        uint256 expires,
        uint256[2][] calldata idsAndAmounts,
        bytes calldata allocatorData
    ) external returns (bytes4);

    /**
     * @notice Check if given allocatorData authorizes a claim. Intended to be called offchain.
     * @param claimHash      The message hash representing the claim.
     * @param arbiter        The account tasked with verifying and submitting the claim.
     * @param sponsor        The account to source the tokens from.
     * @param nonce          A parameter to enforce replay protection, scoped to allocator.
     * @param expires        The time at which the claim expires.
     * @param idsAndAmounts  The allocated token IDs and amounts.
     * @param allocatorData  Arbitrary data provided by the arbiter.
     * @return               A boolean indicating whether the claim is authorized.
     */
    function isClaimAuthorized(
        bytes32 claimHash,
        address arbiter,
        address sponsor,
        uint256 nonce,
        uint256 expires,
        uint256[2][] calldata idsAndAmounts,
        bytes calldata allocatorData
    ) external view returns (bool);
}

File 40 of 41 : 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() }
        }
    }
}

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

interface IEIP712 {
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

Settings
{
  "remappings": [
    "ds-test/=lib/the-compact/lib/permit2/lib/forge-std/lib/ds-test/src/",
    "forge-gas-snapshot/=lib/the-compact/lib/permit2/lib/forge-gas-snapshot/src/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/the-compact/lib/permit2/lib/openzeppelin-contracts/",
    "permit2/=lib/the-compact/lib/permit2/",
    "solady/=lib/solady/src/",
    "soledge/=lib/the-compact/lib/soledge/src/",
    "solmate/=lib/the-compact/lib/permit2/lib/solmate/",
    "the-compact/=lib/the-compact/",
    "tstorish/=lib/the-compact/lib/tstorish/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 4294967295
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": true
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyFilled","type":"error"},{"inputs":[],"name":"DispatchNotAvailable","type":"error"},{"inputs":[],"name":"InvalidAdjustment","type":"error"},{"inputs":[],"name":"InvalidChainId","type":"error"},{"inputs":[],"name":"InvalidCommitmentsArray","type":"error"},{"inputs":[],"name":"InvalidDispatchCallback","type":"error"},{"inputs":[],"name":"InvalidFillBlock","type":"error"},{"inputs":[],"name":"InvalidFillHashArguments","type":"error"},{"inputs":[],"name":"InvalidGasPrice","type":"error"},{"inputs":[],"name":"InvalidPriceCurveParameters","type":"error"},{"inputs":[],"name":"InvalidRecipientCallback","type":"error"},{"inputs":[],"name":"InvalidRecipientCallbackLength","type":"error"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"targetBlockNumber","type":"uint256"}],"name":"InvalidTargetBlock","type":"error"},{"inputs":[],"name":"InvalidTargetBlockDesignation","type":"error"},{"inputs":[],"name":"NotSponsor","type":"error"},{"inputs":[],"name":"PriceCurveBlocksExceeded","type":"error"},{"inputs":[],"name":"ReentrancyGuard","type":"error"},{"inputs":[],"name":"ValidityConditionsNotMet","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sponsor","type":"address"},{"indexed":false,"internalType":"bytes32","name":"claimHash","type":"bytes32"}],"name":"Cancel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"dispatchTarget","type":"address"},{"indexed":true,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"claimant","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"claimHash","type":"bytes32"}],"name":"Dispatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sponsor","type":"address"},{"indexed":true,"internalType":"bytes32","name":"claimant","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"claimHash","type":"bytes32"},{"components":[{"internalType":"uint256","name":"fillAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"indexed":false,"internalType":"struct FillRecipient[]","name":"fillRecipients","type":"tuple[]"},{"indexed":false,"internalType":"uint256[]","name":"claimAmounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"targetBlock","type":"uint256"}],"name":"Fill","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sponsor","type":"address"},{"indexed":true,"internalType":"bytes32","name":"claimant","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"claimHash","type":"bytes32"},{"components":[{"internalType":"uint256","name":"fillAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"indexed":false,"internalType":"struct FillRecipient[]","name":"fillRecipients","type":"tuple[]"},{"indexed":false,"internalType":"uint256[]","name":"claimAmounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"targetBlock","type":"uint256"}],"name":"FillWithClaim","type":"event"},{"inputs":[],"name":"BASE_SCALING_FACTOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"THE_COMPACT","outputs":[{"internalType":"contract ITheCompact","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"arbiter","type":"address"},{"internalType":"address","name":"sponsor","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expires","type":"uint256"},{"components":[{"internalType":"bytes12","name":"lockTag","type":"bytes12"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Lock[]","name":"commitments","type":"tuple[]"}],"internalType":"struct BatchCompact","name":"compact","type":"tuple"},{"internalType":"bytes32","name":"mandateHash","type":"bytes32"}],"name":"cancel","outputs":[{"internalType":"bytes32","name":"claimHash","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"arbiter","type":"address"},{"internalType":"address","name":"sponsor","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expires","type":"uint256"},{"components":[{"internalType":"bytes12","name":"lockTag","type":"bytes12"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Lock[]","name":"commitments","type":"tuple[]"}],"internalType":"struct BatchCompact","name":"compact","type":"tuple"},{"internalType":"bytes32","name":"mandateHash","type":"bytes32"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"context","type":"bytes"}],"internalType":"struct DispatchParameters","name":"dispatchParams","type":"tuple"}],"name":"cancelAndDispatch","outputs":[{"internalType":"bytes32","name":"claimHash","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"arbiter","type":"address"},{"internalType":"address","name":"sponsor","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expires","type":"uint256"},{"components":[{"internalType":"bytes12","name":"lockTag","type":"bytes12"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Lock[]","name":"commitments","type":"tuple[]"}],"internalType":"struct BatchCompact","name":"compact","type":"tuple"},{"internalType":"bytes","name":"sponsorSignature","type":"bytes"},{"internalType":"bytes","name":"allocatorSignature","type":"bytes"}],"internalType":"struct BatchClaim","name":"claim","type":"tuple"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"tribunal","type":"address"},{"internalType":"uint256","name":"expires","type":"uint256"},{"components":[{"internalType":"address","name":"fillToken","type":"address"},{"internalType":"uint256","name":"minimumFillAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bool","name":"applyScaling","type":"bool"}],"internalType":"struct FillComponent[]","name":"components","type":"tuple[]"},{"internalType":"uint256","name":"baselinePriorityFee","type":"uint256"},{"internalType":"uint256","name":"scalingFactor","type":"uint256"},{"internalType":"uint256[]","name":"priceCurve","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"components":[{"internalType":"address","name":"arbiter","type":"address"},{"internalType":"address","name":"sponsor","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expires","type":"uint256"},{"components":[{"internalType":"bytes12","name":"lockTag","type":"bytes12"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Lock[]","name":"commitments","type":"tuple[]"}],"internalType":"struct BatchCompact","name":"compact","type":"tuple"},{"internalType":"bytes32","name":"mandateHash","type":"bytes32"},{"internalType":"bytes","name":"context","type":"bytes"}],"internalType":"struct RecipientCallback[]","name":"recipientCallback","type":"tuple[]"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"internalType":"struct FillParameters","name":"mandate","type":"tuple"},{"components":[{"internalType":"address","name":"adjuster","type":"address"},{"internalType":"uint256","name":"fillIndex","type":"uint256"},{"internalType":"uint256","name":"targetBlock","type":"uint256"},{"internalType":"uint256[]","name":"supplementalPriceCurve","type":"uint256[]"},{"internalType":"bytes32","name":"validityConditions","type":"bytes32"},{"internalType":"bytes","name":"adjustmentAuthorization","type":"bytes"}],"internalType":"struct Adjustment","name":"adjustment","type":"tuple"},{"internalType":"bytes32[]","name":"fillHashes","type":"bytes32[]"},{"internalType":"bytes32","name":"claimant","type":"bytes32"},{"internalType":"uint256","name":"fillBlock","type":"uint256"}],"name":"claimAndFill","outputs":[{"internalType":"bytes32","name":"claimHash","type":"bytes32"},{"internalType":"bytes32","name":"mandateHash","type":"bytes32"},{"internalType":"uint256[]","name":"fillAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"claimAmounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"claimHash","type":"bytes32"}],"name":"claimReductionScalingFactor","outputs":[{"internalType":"uint256","name":"scalingFactor","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes12","name":"lockTag","type":"bytes12"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Lock[]","name":"maximumClaimAmounts","type":"tuple[]"},{"internalType":"uint256[]","name":"priceCurve","type":"uint256[]"},{"internalType":"uint256","name":"targetBlock","type":"uint256"},{"internalType":"uint256","name":"fillBlock","type":"uint256"},{"internalType":"uint256","name":"minimumFillAmount","type":"uint256"},{"internalType":"uint256","name":"baselinePriorityFee","type":"uint256"},{"internalType":"uint256","name":"scalingFactor","type":"uint256"}],"name":"deriveAmounts","outputs":[{"internalType":"uint256","name":"fillAmount","type":"uint256"},{"internalType":"uint256[]","name":"claimAmounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes12","name":"lockTag","type":"bytes12"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Lock[]","name":"maximumClaimAmounts","type":"tuple[]"},{"components":[{"internalType":"address","name":"fillToken","type":"address"},{"internalType":"uint256","name":"minimumFillAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bool","name":"applyScaling","type":"bool"}],"internalType":"struct FillComponent[]","name":"components","type":"tuple[]"},{"internalType":"uint256[]","name":"priceCurve","type":"uint256[]"},{"internalType":"uint256","name":"targetBlock","type":"uint256"},{"internalType":"uint256","name":"fillBlock","type":"uint256"},{"internalType":"uint256","name":"baselinePriorityFee","type":"uint256"},{"internalType":"uint256","name":"scalingFactor","type":"uint256"}],"name":"deriveAmountsFromComponents","outputs":[{"internalType":"uint256[]","name":"fillAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"claimAmounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"arbiter","type":"address"},{"internalType":"address","name":"sponsor","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expires","type":"uint256"},{"components":[{"internalType":"bytes12","name":"lockTag","type":"bytes12"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Lock[]","name":"commitments","type":"tuple[]"}],"internalType":"struct BatchCompact","name":"compact","type":"tuple"},{"internalType":"bytes32","name":"mandateHash","type":"bytes32"}],"name":"deriveClaimHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"fillToken","type":"address"},{"internalType":"uint256","name":"minimumFillAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bool","name":"applyScaling","type":"bool"}],"internalType":"struct FillComponent","name":"component","type":"tuple"}],"name":"deriveFillComponentHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"fillToken","type":"address"},{"internalType":"uint256","name":"minimumFillAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bool","name":"applyScaling","type":"bool"}],"internalType":"struct FillComponent[]","name":"components","type":"tuple[]"}],"name":"deriveFillComponentsHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"tribunal","type":"address"},{"internalType":"uint256","name":"expires","type":"uint256"},{"components":[{"internalType":"address","name":"fillToken","type":"address"},{"internalType":"uint256","name":"minimumFillAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bool","name":"applyScaling","type":"bool"}],"internalType":"struct FillComponent[]","name":"components","type":"tuple[]"},{"internalType":"uint256","name":"baselinePriorityFee","type":"uint256"},{"internalType":"uint256","name":"scalingFactor","type":"uint256"},{"internalType":"uint256[]","name":"priceCurve","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"components":[{"internalType":"address","name":"arbiter","type":"address"},{"internalType":"address","name":"sponsor","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expires","type":"uint256"},{"components":[{"internalType":"bytes12","name":"lockTag","type":"bytes12"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Lock[]","name":"commitments","type":"tuple[]"}],"internalType":"struct BatchCompact","name":"compact","type":"tuple"},{"internalType":"bytes32","name":"mandateHash","type":"bytes32"},{"internalType":"bytes","name":"context","type":"bytes"}],"internalType":"struct RecipientCallback[]","name":"recipientCallback","type":"tuple[]"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"internalType":"struct FillParameters","name":"targetFill","type":"tuple"}],"name":"deriveFillHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"tribunal","type":"address"},{"internalType":"uint256","name":"expires","type":"uint256"},{"components":[{"internalType":"address","name":"fillToken","type":"address"},{"internalType":"uint256","name":"minimumFillAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bool","name":"applyScaling","type":"bool"}],"internalType":"struct FillComponent[]","name":"components","type":"tuple[]"},{"internalType":"uint256","name":"baselinePriorityFee","type":"uint256"},{"internalType":"uint256","name":"scalingFactor","type":"uint256"},{"internalType":"uint256[]","name":"priceCurve","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"components":[{"internalType":"address","name":"arbiter","type":"address"},{"internalType":"address","name":"sponsor","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expires","type":"uint256"},{"components":[{"internalType":"bytes12","name":"lockTag","type":"bytes12"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Lock[]","name":"commitments","type":"tuple[]"}],"internalType":"struct BatchCompact","name":"compact","type":"tuple"},{"internalType":"bytes32","name":"mandateHash","type":"bytes32"},{"internalType":"bytes","name":"context","type":"bytes"}],"internalType":"struct RecipientCallback[]","name":"recipientCallback","type":"tuple[]"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"internalType":"struct FillParameters[]","name":"fills","type":"tuple[]"}],"name":"deriveFillsHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"adjuster","type":"address"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"tribunal","type":"address"},{"internalType":"uint256","name":"expires","type":"uint256"},{"components":[{"internalType":"address","name":"fillToken","type":"address"},{"internalType":"uint256","name":"minimumFillAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bool","name":"applyScaling","type":"bool"}],"internalType":"struct FillComponent[]","name":"components","type":"tuple[]"},{"internalType":"uint256","name":"baselinePriorityFee","type":"uint256"},{"internalType":"uint256","name":"scalingFactor","type":"uint256"},{"internalType":"uint256[]","name":"priceCurve","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"components":[{"internalType":"address","name":"arbiter","type":"address"},{"internalType":"address","name":"sponsor","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expires","type":"uint256"},{"components":[{"internalType":"bytes12","name":"lockTag","type":"bytes12"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Lock[]","name":"commitments","type":"tuple[]"}],"internalType":"struct BatchCompact","name":"compact","type":"tuple"},{"internalType":"bytes32","name":"mandateHash","type":"bytes32"},{"internalType":"bytes","name":"context","type":"bytes"}],"internalType":"struct RecipientCallback[]","name":"recipientCallback","type":"tuple[]"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"internalType":"struct FillParameters[]","name":"fills","type":"tuple[]"}],"internalType":"struct Mandate","name":"mandate","type":"tuple"}],"name":"deriveMandateHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"components":[{"internalType":"address","name":"arbiter","type":"address"},{"internalType":"address","name":"sponsor","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expires","type":"uint256"},{"components":[{"internalType":"bytes12","name":"lockTag","type":"bytes12"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Lock[]","name":"commitments","type":"tuple[]"}],"internalType":"struct BatchCompact","name":"compact","type":"tuple"},{"internalType":"bytes32","name":"mandateHash","type":"bytes32"},{"internalType":"bytes","name":"context","type":"bytes"}],"internalType":"struct RecipientCallback[]","name":"recipientCallback","type":"tuple[]"}],"name":"deriveRecipientCallbackHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"arbiter","type":"address"},{"internalType":"address","name":"sponsor","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expires","type":"uint256"},{"components":[{"internalType":"bytes12","name":"lockTag","type":"bytes12"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Lock[]","name":"commitments","type":"tuple[]"}],"internalType":"struct BatchCompact","name":"compact","type":"tuple"},{"internalType":"bytes32","name":"mandateHash","type":"bytes32"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"context","type":"bytes"}],"internalType":"struct DispatchParameters","name":"dispatchParams","type":"tuple"}],"name":"dispatch","outputs":[{"internalType":"bytes32","name":"claimHash","type":"bytes32"},{"internalType":"uint256[]","name":"claimAmounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"extsload","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"slots","type":"bytes32[]"}],"name":"extsload","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"arbiter","type":"address"},{"internalType":"address","name":"sponsor","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expires","type":"uint256"},{"components":[{"internalType":"bytes12","name":"lockTag","type":"bytes12"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Lock[]","name":"commitments","type":"tuple[]"}],"internalType":"struct BatchCompact","name":"compact","type":"tuple"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"tribunal","type":"address"},{"internalType":"uint256","name":"expires","type":"uint256"},{"components":[{"internalType":"address","name":"fillToken","type":"address"},{"internalType":"uint256","name":"minimumFillAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bool","name":"applyScaling","type":"bool"}],"internalType":"struct FillComponent[]","name":"components","type":"tuple[]"},{"internalType":"uint256","name":"baselinePriorityFee","type":"uint256"},{"internalType":"uint256","name":"scalingFactor","type":"uint256"},{"internalType":"uint256[]","name":"priceCurve","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"components":[{"internalType":"address","name":"arbiter","type":"address"},{"internalType":"address","name":"sponsor","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expires","type":"uint256"},{"components":[{"internalType":"bytes12","name":"lockTag","type":"bytes12"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Lock[]","name":"commitments","type":"tuple[]"}],"internalType":"struct BatchCompact","name":"compact","type":"tuple"},{"internalType":"bytes32","name":"mandateHash","type":"bytes32"},{"internalType":"bytes","name":"context","type":"bytes"}],"internalType":"struct RecipientCallback[]","name":"recipientCallback","type":"tuple[]"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"internalType":"struct FillParameters","name":"mandate","type":"tuple"},{"components":[{"internalType":"address","name":"adjuster","type":"address"},{"internalType":"uint256","name":"fillIndex","type":"uint256"},{"internalType":"uint256","name":"targetBlock","type":"uint256"},{"internalType":"uint256[]","name":"supplementalPriceCurve","type":"uint256[]"},{"internalType":"bytes32","name":"validityConditions","type":"bytes32"},{"internalType":"bytes","name":"adjustmentAuthorization","type":"bytes"}],"internalType":"struct Adjustment","name":"adjustment","type":"tuple"},{"internalType":"bytes32[]","name":"fillHashes","type":"bytes32[]"},{"internalType":"bytes32","name":"claimant","type":"bytes32"},{"internalType":"uint256","name":"fillBlock","type":"uint256"}],"name":"fill","outputs":[{"internalType":"bytes32","name":"claimHash","type":"bytes32"},{"internalType":"bytes32","name":"mandateHash","type":"bytes32"},{"internalType":"uint256[]","name":"fillAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"claimAmounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"arbiter","type":"address"},{"internalType":"address","name":"sponsor","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expires","type":"uint256"},{"components":[{"internalType":"bytes12","name":"lockTag","type":"bytes12"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Lock[]","name":"commitments","type":"tuple[]"}],"internalType":"struct BatchCompact","name":"compact","type":"tuple"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"tribunal","type":"address"},{"internalType":"uint256","name":"expires","type":"uint256"},{"components":[{"internalType":"address","name":"fillToken","type":"address"},{"internalType":"uint256","name":"minimumFillAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bool","name":"applyScaling","type":"bool"}],"internalType":"struct FillComponent[]","name":"components","type":"tuple[]"},{"internalType":"uint256","name":"baselinePriorityFee","type":"uint256"},{"internalType":"uint256","name":"scalingFactor","type":"uint256"},{"internalType":"uint256[]","name":"priceCurve","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"components":[{"internalType":"address","name":"arbiter","type":"address"},{"internalType":"address","name":"sponsor","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expires","type":"uint256"},{"components":[{"internalType":"bytes12","name":"lockTag","type":"bytes12"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Lock[]","name":"commitments","type":"tuple[]"}],"internalType":"struct BatchCompact","name":"compact","type":"tuple"},{"internalType":"bytes32","name":"mandateHash","type":"bytes32"},{"internalType":"bytes","name":"context","type":"bytes"}],"internalType":"struct RecipientCallback[]","name":"recipientCallback","type":"tuple[]"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"internalType":"struct FillParameters","name":"mandate","type":"tuple"},{"components":[{"internalType":"address","name":"adjuster","type":"address"},{"internalType":"uint256","name":"fillIndex","type":"uint256"},{"internalType":"uint256","name":"targetBlock","type":"uint256"},{"internalType":"uint256[]","name":"supplementalPriceCurve","type":"uint256[]"},{"internalType":"bytes32","name":"validityConditions","type":"bytes32"},{"internalType":"bytes","name":"adjustmentAuthorization","type":"bytes"}],"internalType":"struct Adjustment","name":"adjustment","type":"tuple"},{"internalType":"bytes32[]","name":"fillHashes","type":"bytes32[]"},{"internalType":"bytes32","name":"claimant","type":"bytes32"},{"internalType":"uint256","name":"fillBlock","type":"uint256"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"context","type":"bytes"}],"internalType":"struct DispatchParameters","name":"dispatchParameters","type":"tuple"}],"name":"fillAndDispatch","outputs":[{"internalType":"bytes32","name":"claimHash","type":"bytes32"},{"internalType":"bytes32","name":"mandateHash","type":"bytes32"},{"internalType":"uint256[]","name":"fillAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"claimAmounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"claimHash","type":"bytes32"}],"name":"filled","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCompactWitnessDetails","outputs":[{"internalType":"string","name":"witnessTypeString","type":"string"},{"components":[{"internalType":"string","name":"tokenPath","type":"string"},{"internalType":"string","name":"argPath","type":"string"},{"internalType":"string","name":"description","type":"string"}],"internalType":"struct ArgDetail[]","name":"details","type":"tuple[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"claimHashes","type":"bytes32[]"}],"name":"getDispositionDetails","outputs":[{"components":[{"internalType":"bytes32","name":"claimant","type":"bytes32"},{"internalType":"uint256","name":"scalingFactor","type":"uint256"}],"internalType":"struct DispositionDetails[]","name":"details","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"reentrancyGuardStatus","outputs":[{"internalType":"address","name":"lockHolder","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"sourceClaimHash","type":"bytes32"},{"components":[{"internalType":"address","name":"arbiter","type":"address"},{"internalType":"address","name":"sponsor","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expires","type":"uint256"},{"components":[{"internalType":"bytes12","name":"lockTag","type":"bytes12"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Lock[]","name":"commitments","type":"tuple[]"}],"internalType":"struct BatchCompact","name":"compact","type":"tuple"},{"internalType":"bytes32","name":"mandateHash","type":"bytes32"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes","name":"context","type":"bytes"}],"name":"settleOrRegister","outputs":[{"internalType":"bytes32","name":"registeredClaimHash","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c0806040523460b05760a090466080527f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f0e2a7404936dd29a4a3b49dad6c2f86f8e2da9cf7cf60ef9518bb049b4cb9b4460208201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660408201524660608201523060808201522060a0526040516157fa90816100b5823960805181615279015260a051816152580152f35b5f80fdfe6080604052600436101561001a575b3615610018575f80fd5b005b5f5f3560e01c806306fdde03146124055780630e71a7bf146120c7578063132e3a2314611e265780631e2eaeaf14611dec57806321eaf4cc14611c66578063288cdc9114611c1f5780633540346214611b9957806342b16dd714611b295780634c73f1d214611acf578063533e1aef14611a5657806353e09f0f146119fc578063542c0792146119bc57806356d5b3e014611958578063595be4491461193f5780635e7ef41d1461177c57806373e37b23146116945780637f8f3ea61461161857806380008e37146114d7578063a2cc82f514611329578063dbd035ff14611293578063e2a17a5714611092578063e84dded61461104d578063ee75775e14610f69578063ef74074f14610e13578063f0b6dce414610db15763f71b182814610143575061000e565b60c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af3576004359067ffffffffffffffff8211610af35760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8336030112610af35767ffffffffffffffff60243511610af3576101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60243536030112610af35767ffffffffffffffff60443511610af35760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60443536030112610af35760643567ffffffffffffffff8111610af35761024b9036906004016126c8565b7f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c09291925c610da4576102c56102f491337f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d6102a960a435614642565b94856004604435016102ba8161310b565b602435600401614e56565b926102e06102d66004870180612c74565b6080810190612be7565b906044356004019160243560040191615003565b9491936103046004840180612c74565b906103156024850185600401612ca7565b9490956103286044830183600401612ca7565b9760405197610100890189811067ffffffffffffffff821117610af75761039d936103949160409e9d9e5260608b52606060208c01525f60408c01525f60608c01525f60808c01525f60a08c0152606060c08c0152606060e08c015261038c6157ce565b9b3691614682565b89523691614682565b602087015273ffffffffffffffffffffffffffffffffffffffff6103c36020860161310b565b16604087015260408401356060870152606084013560808701528260a08701526103eb6127f1565b60c087015284517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061043561041f8361256b565b9261042d604051948561252a565b80845261256b565b015f5b818110610d8757505060e08701526040985f5b8651811015610597577fffffffffffffffffffffffff000000000000000000000000000000000000000061049461048f8361048960808b018b612be7565b90612bca565b6132f2565b1673ffffffffffffffffffffffffffffffffffffffff6104c660206104c08561048960808d018d612be7565b0161310b565b161789528a6104dc8261048960808a018a612be7565b013560208a01528a516104ef8c8261252a565b600181525f5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08d0181106105755750908160019260408c015261053560843591612b0d565b51526105418189612b47565b51602061055160408d0151612b0d565b51015261056e8160e08b01518c6105688383612b47565b52612b47565b500161044b565b6020908d516105838161250e565b5f81525f83820152828285010152016104f5565b50899087878b886105a78161310b565b3073ffffffffffffffffffffffffffffffffffffffff821614610d73575b865180957f6428cb590000000000000000000000000000000000000000000000000000000082526020600483015260e06106b96106476106138451610100602488015261012487019061247e565b60208501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc87830301604488015261247e565b73ffffffffffffffffffffffffffffffffffffffff604085015116606486015260608401516084860152608084015160a486015260a084015160c486015260c08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc8683030160e487015261247e565b910151907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc83820301610104840152815180825260208201916020808360051b8301019401925f915b8d848410610cd45750505050505091815f73ffffffffffffffffffffffffffffffffffffffff826020960393165af1938415610c2b575f94610ca0575b50610754606460243501602435600401613180565b9050610990575b50670de0b6b3a7640000811061097e575b506107da61077e60443560040161310b565b6107b6610790856044356004016151de565b610798615256565b90919091604051926119015f526020526040526042601e2091604052565b6107d46107cd60a460443501604435600401612ca7565b3691614682565b91615326565b15610956576107ee8360243560040161544c565b61080c610805606460243501602435600401613180565b90506146e6565b94805b610823606460243501602435600401613180565b90508110156108a1578061083960019287612b47565b5173ffffffffffffffffffffffffffffffffffffffff610871896104c08561086b606460243501602435600401613180565b90612ff2565b89519261087d8461250e565b835216602082015261088f828a612b47565b5261089a8189612b47565b500161080f565b5090939195946108c060206104c0610952988060040190600401612c74565b907fe2158b757579e39997b81ac181c3fd651ef57041e5da67df952949106a0ea4e78451806109128b8a73ffffffffffffffffffffffffffffffffffffffff608435981696604480350135928561475e565b0390a361092683888860243560040161554b565b7f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d519485948561279d565b0390f35b6004857f79f9cc43000000000000000000000000000000000000000000000000000000008152fd5b8286526001602052848620558761076c565b96929095916109ad606460249a96979a3501602435600401613180565b9790507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06109f26109dd8a61256b565b996109ea8d519b8c61252a565b808b5261256b565b015f5b818110610c785750505f5b610a14606460243501602435600401613180565b9050811015610b2457610a358161086b606460243501602435600401613180565b90608082360312610af3578b5191608083019280841067ffffffffffffffff851117610af7578d9384526060610a6a836127d0565b92838352602081013595866020850152610a858183016127d0565b908401520135938415158503610af35773ffffffffffffffffffffffffffffffffffffffff8f92858e6001986060610abe940152612b47565b51925193610acb856124f2565b16835260208301528d820152610ae1828c612b47565b52610aec818b612b47565b5001610a00565b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b50919397610b3e9099969599979193976080810190612be7565b9190333b15610af3579190610bbe610b8e89519485947fdc5620dc000000000000000000000000000000000000000000000000000000008652896004870152608060248701526084860191613fcd565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc848203016044850152866125e0565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc838203016064840152602080835192838152019201905f5b818110610c355750505090805f92038183335af18015610c2b571561075b57610c239196505f9061252a565b5f948861075b565b86513d5f823e3d90fd5b8251805173ffffffffffffffffffffffffffffffffffffffff16855260208181015181870152908c01518c86015286955060609094019390920191600101610bf7565b6020908c5f815191610c89836124f2565b818352818584015282015282828d010152016109f5565b9093506020813d602011610ccc575b81610cbc6020938361252a565b81010312610af35751928961073f565b3d9150610caf565b509193955091937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08282030183528c8651602060808360608601938051875283810151848801520151946060858201528551809452019301915f905b828210610d53575050505060208060019297019301930190928a95949293610702565b83518051865260209081015181870152940193909201916001018f610d30565b506c171ede64904551eedf3c6c97886105c5565b602090610d959c9b9c6157ce565b828286010152019a999a610438565b638beb9d165f526004601cfd5b34610af35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043567ffffffffffffffff8111610af357610e0b610e0560209236906004016126c8565b90613c13565b604051908152f35b60a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760243567ffffffffffffffff8111610af35760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8236030112610af3576064359073ffffffffffffffffffffffffffffffffffffffff82168203610af3576084359067ffffffffffffffff8211610af35736602383011215610af35781600401359067ffffffffffffffff8211610af3573660248385010111610af3577f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05c610da4576020936024610f3e94337f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d019160443590600401600435613378565b5f7f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d604051908152f35b34610af35760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043573ffffffffffffffffffffffffffffffffffffffff811690818103610af357506044359073ffffffffffffffffffffffffffffffffffffffff821691828103610af3575060643591821515808403610af3576020935060405191848301937f97a135285706d21a6b74ac159b77b16cea827acc358fc6c33e430ce0a85fe9d6855260408401526024356060840152608083015260a082015260a0815261104260c08261252a565b519020604051908152f35b34610af3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760206040516c171ede64904551eedf3c6c97888152f35b60e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043567ffffffffffffffff8111610af35760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc826004019236030112610af3576024359067ffffffffffffffff8211610af3576101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8336030112610af35760443567ffffffffffffffff8111610af35760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8236030112610af35760643567ffffffffffffffff8111610af35761119c9036906004016126c8565b9390916084359160c4359567ffffffffffffffff8711610af35760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8836030112610af3577f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05c610da45761095294611264938561125194337f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d61124360a435614642565b92600401906004018a6147db565b9483838793969599949a6004019461411f565b5f7f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d6040519485948561279d565b34610af35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043567ffffffffffffffff8111610af3576112e29036906004016126c8565b6040519160408360208152836020820152019160051b83019060206040830191935b8435548152019284828510156113205750602080910193611304565b60408185030190f35b34610af35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043567ffffffffffffffff8111610af3576113789036906004016126c8565b906113828261256b565b91611390604051938461252a565b8083527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06113bd8261256b565b015f5b8181106114b45750505f5b81811061142357836040518091602082016020835281518091526020604084019201905f5b8181106113fe575050500390f35b82518051855260209081015181860152869550604090940193909201916001016113f0565b8061143160019284866132d5565b35805f525f60205261148460405f2054915f52600160205260405f20547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff670de0b6b3a764000082150282179114150290565b604051916114918361250e565b825260208201526114a28287612b47565b526114ad8186612b47565b50016113cb565b6020906040516114c38161250e565b5f81525f83820152828288010152016113c0565b34610af35760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043567ffffffffffffffff8111610af3576115269036906004016124c1565b9060243567ffffffffffffffff8111610af3576115479036906004016126f9565b9060443567ffffffffffffffff8111610af357611568903690600401612583565b9061157d60c4359260843590606435906149ef565b9261159d8484670de0b6b3a7640000808084118184111493149114171790565b156115f0576115e2956115c86115bd610952966115ce9660a43591614a52565b949080948692614af6565b95614b81565b6040519384936040855260408501906125e0565b9083820360208501526125e0565b7fe80f2482000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610af35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043567ffffffffffffffff8111610af3576101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8236030112610af357610e0b602091600401613208565b34610af35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043567ffffffffffffffff8111610af357806004019060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8236030112610af357611722610e0583602461171a60209661310b565b94019061312c565b6040519073ffffffffffffffffffffffffffffffffffffffff848301937fd98eceb6e5c7770b3b664a99c269855402fe5255294a30970d25376caea662c6855216604083015260608201526060815261104260808261252a565b60c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043567ffffffffffffffff8111610af35760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8236030112610af35760243567ffffffffffffffff8111610af3576101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8236030112610af3576044359167ffffffffffffffff8311610af35760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8436030112610af35760643567ffffffffffffffff8111610af3576118829036906004016126c8565b917f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05c610da457610952946118f494337f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d6118df60a435614642565b926084359260040191600401906004016147db565b90939193478061192f575b505f7f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d6040519485948561279d565b61193990336149d3565b856118ff565b34610af3576020610e0b6119523661272a565b906144ae565b34610af3576119663661272a565b907f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05c610da457602091610f3e91337f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d614393565b34610af3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af3576020604051670de0b6b3a76400008152f35b34610af35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043567ffffffffffffffff8111610af357610e0b611a5060209236906004016126f9565b9061302f565b34610af35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af3576020610e0b6004355f52600160205260405f20547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff670de0b6b3a764000082150282179114150290565b34610af35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043567ffffffffffffffff8111610af357610e0b611b2360209236906004016126c8565b90612d36565b34610af3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760207f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05c73ffffffffffffffffffffffffffffffffffffffff60405191168152f35b611ba236612613565b91907f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05c610da457602092610f3e91337f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d611bfe8185614393565b9384611c17611c106080840184612be7565b9050612b5b565b92339261411f565b34610af35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af3576004355f525f602052602060405f2054604051908152f35b611c6f36612613565b7f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05c610da457337f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d611cc282846144ae565b90815f525f60205260405f2054938415611dc457611d1c835f52600160205260405f20547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff670de0b6b3a764000082150282179114150290565b926080820192611d2f611c108585612be7565b965f5b88611d3d8787612be7565b9050821015611d76575080611d65886040611d5e6001956104898c8c612be7565b0135613f1a565b611d6f828c612b47565b5201611d32565b84611d85858386848e8c61411f565b5f7f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d61095260405192839283526040602084015260408301906125e0565b7fe0d88415000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610af35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af357600435545f5260205ff35b34610af35760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043567ffffffffffffffff8111610af357611e759036906004016124c1565b9060243567ffffffffffffffff8111610af357611e96903690600401612583565b608435929060c43590604435606435670de0b6b3a7640000821561209357508082116120655790611ec992910390613c94565b935b611eea8583670de0b6b3a7640000808084118184111493149114171790565b156115f057611efa60a435613ed6565b611f0384612b5b565b95670de0b6b3a7640000841480612053575b670de0b6b3a764000085111715611fe8577ffffffffffffffffffffffffffffffffffffffffffffffffff21f494c589c00008401938411611fbb57611f60611f6692611f6c95612bb7565b90612bda565b90613f68565b915f5b8451811015611f9b57806040611f886001938686612bca565b0135611f948288612b47565b5201611f6f565b5050505b61095260405192839283526040602084015260408301906125e0565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b90919392670de0b6b3a764000003670de0b6b3a76400008111611fbb576120189261201291612bb7565b90612baa565b91925f5b855181101561204a5780612039856040611d5e6001958888612bca565b6120438289612b47565b520161201c565b50505050611f9f565b50670de0b6b3a7640000811015611f15565b7f97417ef2000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b96929150505115611ecb575b7f97206b56000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610af3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af3576020612190600160286121066127f1565b6040519485917f4d616e6461746528000000000000000000000000000000000000000000000000828401528051918291018484015e81017f29000000000000000000000000000000000000000000000000000000000000008382015203017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181018452018261252a565b604080519061219f818361252a565b600182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015f5b8181106123db5761232785858580516121e0816124f2565b81516121ec838261252a565b601e81527f66696c6c735b5d2e636f6d706f6e656e74735b5d2e66696c6c546f6b656e000060208201528152606090825161222860608261252a565b602681527f66696c6c735b5d2e636f6d706f6e656e74735b5d2e6d696e696d756d46696c6c60208201527f416d6f756e740000000000000000000000000000000000000000000000000000848201526020820152825161228960808261252a565b604a81527f4f757470757420746f6b656e20616e64206d696e696d756d20616d6f756e742060208201527f666f7220656163682066696c6c20636f6d706f6e656e7420696e207468652046848201527f696c6c732061727261790000000000000000000000000000000000000000000060608201528382015261230b84612b0d565b5261231583612b0d565b5081519485948386528386019061247e565b848103602086015283519182825260208201906020808560051b8501019601945f935b8585106123575788880389f35b91939597509193956020806123c7837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe086600196030189528b5190876123b76123a784518c85528c85019061247e565b868501518482038886015261247e565b920151908881840391015261247e565b99019501950192909188979694959261234a565b60209083516123e9816124f2565b60608152606083820152606085820152828287010152016121c8565b34610af3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35761095260405161244460408261252a565b600881527f54726962756e616c00000000000000000000000000000000000000000000000060208201526040519182916020835260208301905b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b9181601f84011215610af35782359167ffffffffffffffff8311610af35760208085019460608502010111610af357565b6060810190811067ffffffffffffffff821117610af757604052565b6040810190811067ffffffffffffffff821117610af757604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610af757604052565b67ffffffffffffffff8111610af75760051b60200190565b9080601f83011215610af357813561259a8161256b565b926125a8604051948561252a565b81845260208085019260051b820101928311610af357602001905b8282106125d05750505090565b81358152602091820191016125c3565b90602080835192838152019201905f5b8181106125fd5750505090565b82518452602093840193909201916001016125f0565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc820112610af35760043567ffffffffffffffff8111610af35760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8284030112610af35760040191602435916044359067ffffffffffffffff8211610af3577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82608092030112610af35760040190565b9181601f84011215610af35782359167ffffffffffffffff8311610af3576020808501948460051b010111610af357565b9181601f84011215610af35782359167ffffffffffffffff8311610af3576020808501948460071b010111610af357565b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc820112610af3576004359067ffffffffffffffff8211610af3577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8260a092030112610af3576004019060243590565b926127cd94926127bf92855260208501526080604085015260808401906125e0565b9160608184039101526125e0565b90565b359073ffffffffffffffffffffffffffffffffffffffff82168203610af357565b604051906128016102a08361252a565b61027b82527f6d7061637420636f6d706163742c627974657320636f6e746578740000000000610280837f616464726573732061646a75737465722c4d616e646174655f46696c6c5b5d2060208201527f66696c6c73294d616e646174655f4261746368436f6d7061637428616464726560408201527f737320617262697465722c616464726573732073706f6e736f722c75696e743260608201527f3536206e6f6e63652c75696e7432353620657870697265732c4d616e6461746560808201527f5f4c6f636b5b5d20636f6d6d69746d656e74732c4d616e64617465206d616e6460a08201527f617465294d616e646174655f46696c6c2875696e7432353620636861696e496460c08201527f2c616464726573732074726962756e616c2c75696e743235362065787069726560e08201527f732c4d616e646174655f46696c6c436f6d706f6e656e745b5d20636f6d706f6e6101008201527f656e74732c75696e7432353620626173656c696e655072696f726974794665656101208201527f2c75696e74323536207363616c696e67466163746f722c75696e743235365b5d6101408201527f20707269636543757276652c4d616e646174655f526563697069656e7443616c6101608201527f6c6261636b5b5d20726563697069656e7443616c6c6261636b2c6279746573336101808201527f322073616c74294d616e646174655f46696c6c436f6d706f6e656e74286164646101a08201527f726573732066696c6c546f6b656e2c75696e74323536206d696e696d756d46696101c08201527f6c6c416d6f756e742c6164647265737320726563697069656e742c626f6f6c206101e08201527f6170706c795363616c696e67294d616e646174655f4c6f636b286279746573316102008201527f32206c6f636b5461672c6164647265737320746f6b656e2c75696e74323536206102208201527f616d6f756e74294d616e646174655f526563697069656e7443616c6c6261636b6102408201527f2875696e7432353620636861696e49642c4d616e646174655f4261746368436f6102608201520152565b805115612b1a5760200190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b8051821015612b1a5760209160051b010190565b90612b658261256b565b612b72604051918261252a565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0612ba0829461256b565b0190602036910137565b91908203918211611fbb57565b81810292918115918404141715611fbb57565b9190811015612b1a576060020190565b91908201809211611fbb57565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610af3570180359067ffffffffffffffff8211610af357602001916060820236038313610af357565b9015612b1a578035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8181360301821215610af3570190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6181360301821215610af3570190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610af3570180359067ffffffffffffffff8211610af357602001918136038313610af357565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b9080612d625750507fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47090565b60018103612fca57612d7391612c3b565b612d806020820182612c74565b612d8d6080820182612be7565b90612d9782612b5b565b915f5b818110612f0457505050612dc191612ee291604051612ded81612dc1602082018095613002565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0810183528261252a565b51902090612dfa8161310b565b916060612e096020840161310b565b9273ffffffffffffffffffffffffffffffffffffffff604051948160208701977f75d7205b7ec9e9b203d9161387d95a46c8440f4530dceab1bb28d4194a5862278952166040870152168285015260408101356080850152013560a083015260c0820152604085013560e082015260e08152612e876101008261252a565b519020612e976060850185612ca7565b939060405194859360208501977fb60a17eb6828a433f2f2fcbeb119166fa25e1fb6ae3866e33952bb74f50550318952356040860152606085015260808085015260a0840191612cf8565b5190206040516020810191825260208152612efe60408261252a565b51902090565b80612f1561048f6001938587612bca565b612f2560206104c0848789612bca565b6040612f32848789612bca565b013573ffffffffffffffffffffffffffffffffffffffff604051927fffffffffffffffffffffffff000000000000000000000000000000000000000060208501957fce4f0854d9091f37d9dfb64592eee0de534c6680a5444fd55739b61228a6e0b08752166040850152166060830152608082015260808152612fb660a08261252a565b519020612fc38287612b47565b5201612d9a565b7fa3cb8f80000000000000000000000000000000000000000000000000000000005f5260045ffd5b9190811015612b1a5760071b0190565b80516020909101905f5b8181106130195750505090565b825184526020938401939092019160010161300c565b61303882612b5b565b915f5b81811061305a57505050604051612efe81612dc1602082018095613002565b806130686001928486612ff2565b6130718161310b565b9061307e6040820161310b565b73ffffffffffffffffffffffffffffffffffffffff61309f606084016132e5565b9160206040519483828701977f97a135285706d21a6b74ac159b77b16cea827acc358fc6c33e430ce0a85fe9d6895216604087015201356060850152166080830152151560a082015260a081526130f760c08261252a565b5190206131048287612b47565b520161303b565b3573ffffffffffffffffffffffffffffffffffffffff81168103610af35790565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610af3570180359067ffffffffffffffff8211610af357602001918160051b36038313610af357565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610af3570180359067ffffffffffffffff8211610af357602001918160071b36038313610af357565b91907f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8111610af35760051b809282370190565b613218611a506060830183613180565b90610100613243612dc161322f60c085018561312c565b9290604051928391602083019586916131d4565b51902091613257611b2360e083018361312c565b6040519360208501957f1d0ee69a7bc1ac54d9a6b38f32ab156fbfe09a9098843d54f89e7b1033533d3387524660408701523060608701526040840135608087015260a0860152608083013560c086015260a083013560e08601528385015261012084015201356101408201526101408152612efe6101608261252a565b9190811015612b1a5760051b0190565b358015158103610af35790565b357fffffffffffffffffffffffff000000000000000000000000000000000000000081168103610af35790565b90602080835192838152019201905f5b81811061333c5750505090565b909192835181905f915b600283106133625750505060400192602001919060010161332f565b6020806001928451815201920192019190613346565b90929593959491946080840160016133908287612be7565b905003613beb576133a19085612be7565b90929015612b1a575f525f60205260405f205480613b7057506133c66020850161310b565b811502187fffffffffffffffffffffffff00000000000000000000000000000000000000006133f4836132f2565b1615613b1b5760409283519261340a858561252a565b600184527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe085015f5b818110613afc5750505f9060207fffffffffffffffffffffffff000000000000000000000000000000000000000061346a836132f2565b1691019073ffffffffffffffffffffffffffffffffffffffff61348c8361310b565b161761349786612b0d565b515273ffffffffffffffffffffffffffffffffffffffff6134b78261310b565b1661394e57505047918260206134cc86612b0d565b5101525b871561388b575084840135806137f257506134ea83612b0d565b5151978451987f5b15bfd9000000000000000000000000000000000000000000000000000000008a5260048a015260a0896024816c171ede64904551eedf3c6c97885afa9283156137e85788995f99989994613756575b5061354e6020880161310b565b6135578861310b565b90848489519d8e947f7ef6597a00000000000000000000000000000000000000000000000000000000865260608d0135908b600488019661359797614d19565b038a73ffffffffffffffffffffffffffffffffffffffff861691815a6020945f91f18015610c2b5788999a5f9997989991613721575b506135da60208a0161310b565b906135e48a61310b565b89517fe9626d0c0000000000000000000000000000000000000000000000000000000081529b8c9384936136239360608f0135928c9060048801614c86565b03815a936c171ede64904551eedf3c6c97885f95f1978815610c2b575f986136fc575b506136536020880161310b565b9461365d8861310b565b9773ffffffffffffffffffffffffffffffffffffffff85163b15610af3576136d46060945f989473ffffffffffffffffffffffffffffffffffffffff948a968c519d8e9b8c9a8b987f89336227000000000000000000000000000000000000000000000000000000008a5201359260048901614d19565b0393165af19081156136f357506136e9575090565b5f6127cd9161252a565b513d5f823e3d90fd5b6137199198503d805f833e613711818361252a565b810190614c04565b50965f613646565b9650506020863d60201161374e575b8161373d6020938361252a565b81010312610af3578895515f6135cd565b3d9150613730565b9750925060a0873d60a0116137e0575b8161377360a0938361252a565b81010312610af35761378487614cf8565b5061379160208801614cf8565b966008868201511015610af357600260608201511015610af357608001517fffffffffffffffffffffffff0000000000000000000000000000000000000000811603610af3578896925f613541565b3d9150613766565b85513d5f823e3d90fd5b959750509091948361384f60609261380d60205f980161310b565b6138168461310b565b988a51998a98899788977fe9626d0c00000000000000000000000000000000000000000000000000000000895201359360048801614c86565b03916c171ede64904551eedf3c6c97885af19182156136f357505f91613873575090565b61388791503d805f833e613711818361252a565b5090565b9650509082949650602093506138ec9073ffffffffffffffffffffffffffffffffffffffff9351968794859384937f456b7d0c000000000000000000000000000000000000000000000000000000008552896004860152604485019061331f565b9116602483015203916c171ede64904551eedf3c6c97885af19081156136f3575061391657505f90565b6020813d602011613946575b8161392f6020938361252a565b81010312610af357518015158103610af357505f90565b3d9150613922565b602080602460106139618598969861310b565b306014526f70a082310000000000000000000000005f525afa601f3d111660205102602061398e87612b0d565b510152602080604460106139a18561310b565b306014526c171ede64904551eedf3c6c97886034526fdd62ed3e0000000000000000000000005f525afa601f3d1116602051025f60345260206139e387612b0d565b510151116139f2575b506134d0565b6139fb9061310b565b6c171ede64904551eedf3c6c97886014527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6034526f095ea7b30000000000000000000000005f5260205f6044601082855af18060015f51141615613a67575b50505f6034525f6139ec565b3d823b15171015613a79575b80613a5b565b5f6034526f095ea7b30000000000000000000000005f525f386044601083855af1507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60345260205f6044601082855af1908160015f51141615613ade575b50613a73565b3b153d171015613aef575f80613ad8565b633e3f8f735f526004601cfd5b6020908751613b0b898261252a565b8836823782828901015201613433565b94509150506020919350019073ffffffffffffffffffffffffffffffffffffffff613b458361310b565b16613b5a57613b56915047906149d3565b5f90565b613b66613b6b9261310b565b615753565b505f90565b9550509150506020919350019073ffffffffffffffffffffffffffffffffffffffff613b9b8361310b565b16613bc257613b56915073ffffffffffffffffffffffffffffffffffffffff4791166149d3565b73ffffffffffffffffffffffffffffffffffffffff613be3613b6b9361310b565b911690615753565b7f02492d60000000000000000000000000000000000000000000000000000000005f5260045ffd5b91613c1d82612b5b565b905f5b83811015613c7a578060051b850135907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee186360301821215610af357613c696001928701613208565b613c738286612b47565b5201613c20565b5092509050604051612efe81612dc1602082018095613002565b9091815115613ec7575f9081805b8451841015613e8f57613cb58486612b47565b51907dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260f01c92168215613e6457613cec8383612bda565b8810613d085750600191613cff91612bda565b935b0192613ca2565b9396928096929695919590613e25575b15613db2577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908111611fbb57613d5091612b47565b517dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1692670de0b6b3a76400008085148185141781861191851191909114175b156115f057613da06127cd9582612bda565b92670de0b6b3a7640000851194614d95565b92939260018101908110611fbb578151811015613e1457613dd291612b47565b517dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16915b613d8e8385670de0b6b3a7640000808084118184111493149114171790565b5050670de0b6b3a764000091613df5565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818111611fbb57613e5a9083612b47565b5160f01c15613d18565b9080959250871015613e7a575b50600190613d01565b60019250848703613e71579450505092505090565b9350509290501015613e9f575f90565b7f89cc9952000000000000000000000000000000000000000000000000000000005f5260045ffd5b915050670de0b6b3a764000090565b483a10613ef257483a0381811115613eec570390565b50505f90565b7ff3eb44e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211613f54575b670de0b6b3a764000091020490565b8015613f45575b63bac65e5b5f526004601cfd5b908082029181830403613f8b575b50670de0b6b3a7640000808204910615150190565b613f5b575f613f76565b90816020910312610af357517fffffffff0000000000000000000000000000000000000000000000000000000081168103610af35790565b916020908281520191905f905b808210613fe75750505090565b9091928335907fffffffffffffffffffffffff00000000000000000000000000000000000000008216809203610af35760608160019382935273ffffffffffffffffffffffffffffffffffffffff614041602089016127d0565b16602082015260408701356040820152019401920190613fda565b73ffffffffffffffffffffffffffffffffffffffff61407a826127d0565b16825273ffffffffffffffffffffffffffffffffffffffff61409e602083016127d0565b166020830152604081013560408301526060810135606083015260808101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe182360301811215610af357016020813591019067ffffffffffffffff8111610af3576060810236038213610af35760a0838160806127cd9601520191613fcd565b91929490938561416b855f52600160205260405f20547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff670de0b6b3a764000082150282179114150290565b92602081019461417a8661310b565b73ffffffffffffffffffffffffffffffffffffffff16938235988991606085016141a49086612ca7565b919092604051998a98899788977f401722d4000000000000000000000000000000000000000000000000000000008952600489015260248801610100905261010488016141f09161405c565b9260448801528d6064880152608487015260a48601528481037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0160c4860152614239916125e0565b908382037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0160e485015261426d92612cf8565b0391604001355a94602095f1908115614388577f401722d400000000000000000000000000000000000000000000000000000000917fffffffff00000000000000000000000000000000000000000000000000000000915f91614359575b50160361433157602073ffffffffffffffffffffffffffffffffffffffff6143137f6d55a93a63f6b120c85df7abd40f86808b20899b13ee33928427bb8827727e669361310b565b1692604051908152a447806143255750565b61432f90336149d3565b565b7ff0a08c77000000000000000000000000000000000000000000000000000000005f5260045ffd5b61437b915060203d602011614381575b614373818361252a565b810190613f95565b5f6142cb565b503d614369565b6040513d5f823e3d90fd5b602081019173ffffffffffffffffffffffffffffffffffffffff6143b68461310b565b163303614486576143c6916144ae565b90815f525f60205260405f205461445e5761443073ffffffffffffffffffffffffffffffffffffffff91835f525f6020523360405f2055835f5260016020527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60405f205561310b565b167fdb2b33dd6349739e1f3cd6dc90cf093af6a3dfb1838aced380528b0aefe6093c6020604051848152a290565b7f41a26a63000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fdf4795c7000000000000000000000000000000000000000000000000000000005f5260045ffd5b6144bb6080820182612be7565b906144c582612b5b565b915f5b81811061457c575050506040516144e781612dc1602082018095613002565b519020916144f48261310b565b9260606145036020850161310b565b9373ffffffffffffffffffffffffffffffffffffffff604051958160208801987fdbbdcf42471b4a26f7824df9f33f0a4f9bb4e7a66be6a31be8868a6cbbec0a7d8a52166040880152168286015260408101356080860152013560a084015260c083015260e082015260e08152612efe6101008261252a565b8061458d61048f6001938587612bca565b61459d60206104c0848789612bca565b60406145aa848789612bca565b013573ffffffffffffffffffffffffffffffffffffffff604051927fffffffffffffffffffffffff000000000000000000000000000000000000000060208501957ffb7744571d97aa61eb9c2bc3c67b9b1ba047ac9e95afb2ef02bc5b3d9e64fbe5875216604085015216606083015260808201526080815261462e60a08261252a565b51902061463b8287612b47565b52016144c8565b9061464b614dd9565b91828115021891820361465a57565b7f5345d2f0000000000000000000000000000000000000000000000000000000005f5260045ffd5b92919267ffffffffffffffff8211610af757604051916146ca601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0166020018461252a565b829481845281830111610af3578281602093845f960137010152565b906146f08261256b565b6146fd604051918261252a565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061472b829461256b565b01905f5b82811061473b57505050565b60209060405161474a8161250e565b5f81525f838201528282850101520161472f565b9493929060808601908652608060208701528251809152602060a087019301905f5b8181106147a3575050508161479e91866060940360408801526125e0565b930152565b82518051865260209081015173ffffffffffffffffffffffffffffffffffffffff168187015260409095019490920191600101614780565b9461480f91949297966147f991848a6147f38161310b565b89614e56565b9187856148096080890189612be7565b90615003565b929193909687908592614822858a6144ae565b95865f525f60205260405f205461445e57865f525f6020528160405f2055670de0b6b3a764000081106149c0575b5061487c61485d8c61310b565b8c6107d46107cd6148716107908c856151de565b9260a0810190612ca7565b15614998576148ae9a61488f888a61544c565b606089019a6148a16108058d8c613180565b9a8c5f9e8f915b8d613180565b9190501015614925576148ae60018e9f8f8f8f908f9173ffffffffffffffffffffffffffffffffffffffff6148fb60406104c08861086b61491a996148f483809b612b47565b5197613180565b604051926149088461250e565b83521660208201526105688383612b47565b50019e908f916148a8565b889d50879c507f79250a3d76a8bc9cbf78119657750fb9310acddd28a27c2df2691226108fd3c79161499061432f9a979c969b99989d61497c602073ffffffffffffffffffffffffffffffffffffffff950161310b565b926040805195869516970135918a8561475e565b0390a361554b565b7f79f9cc43000000000000000000000000000000000000000000000000000000005f5260045ffd5b865f52600160205260405f20555f614850565b5f80809338935af1156149e257565b63b12d13eb5f526004601cfd5b909291670de0b6b3a76400008415614a465750808411614a1657926127cd92930390613c94565b83907f97417ef2000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b929350505161209f5790565b909291614a5e90613ed6565b90670de0b6b3a7640000841480614ae4575b670de0b6b3a7640000851117938415614abe577ffffffffffffffffffffffffffffffffffffffffffffffffff21f494c589c00008101908111611fbb57614aba92611f6091612bb7565b9190565b670de0b6b3a764000003670de0b6b3a76400008111611fbb57614aba9261201291612bb7565b50670de0b6b3a7640000811015614a70565b929190614b0281612b5b565b935f5b828110614b1457505050505090565b80614b2d6060614b276001948787612ff2565b016132e5565b15614b62578515614b6257614b50856020614b49848888612ff2565b0135613f68565b614b5a8289612b47565b525b01614b05565b6020614b6f828686612ff2565b0135614b7b8289612b47565b52614b5c565b90939291614b8e85612b5b565b9215614bca57505f5b8251811015614bc357806040614bb06001938886612bca565b0135614bbc8286612b47565b5201614b97565b5090925050565b93905f5b8351811015614bfc5780614beb876040611d5e6001958888612bca565b614bf58287612b47565b5201614bce565b509193505050565b9190604083820312610af35782519260208101519067ffffffffffffffff8211610af357019080601f83011215610af3578151614c408161256b565b92614c4e604051948561252a565b81845260208085019260051b820101928311610af357602001905b828210614c765750505090565b8151815260209182019101614c69565b9296959491614cbd73ffffffffffffffffffffffffffffffffffffffff918260c0979416865260e0602087015260e086019061331f565b97166040840152606083015260808201527fdbbdcf42471b4a26f7824df9f33f0a4f9bb4e7a66be6a31be8868a6cbbec0a7d60a08201520152565b519073ffffffffffffffffffffffffffffffffffffffff82168203610af357565b92959390614d516127cd98969373ffffffffffffffffffffffffffffffffffffffff809316865260e0602087015260e086019061331f565b9616604084015260608301527fdbbdcf42471b4a26f7824df9f33f0a4f9bb4e7a66be6a31be8868a6cbbec0a7d608083015260a082015260c0818503910152612cf8565b9190949293858303614da957505050505090565b91614dc682611f6093614dcc969798950397039182880390612bb7565b92612bb7565b9181830304019015150290565b4661a4b103614e52576040517fa3b1b31d00000000000000000000000000000000000000000000000000000000815260208160048160645afa908115614388575f91614e23575090565b90506020813d602011614e4a575b81614e3e6020938361252a565b81010312610af3575190565b3d9150614e31565b4390565b9190949392604083013542811115614ff3575046833503614fcb5760808201359073ffffffffffffffffffffffffffffffffffffffff82169160a01c90614ea1826040860135612bda565b1115901515169073ffffffffffffffffffffffffffffffffffffffff3391338115021816141517614fa357602001359083821091821592614f82575b5050614f5a57614efc612dc191604051928391602083019586916131d4565b5190206040519073ffffffffffffffffffffffffffffffffffffffff60208301937fd98eceb6e5c7770b3b664a99c269855402fe5255294a30970d25376caea662c68552166040830152606082015260608152612efe60808261252a565b7f838a8d5f000000000000000000000000000000000000000000000000000000005f5260045ffd5b614f9a919250614f939085856132d5565b3591613208565b14155f80614edd565b7f6770cd44000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f7a47c9a2000000000000000000000000000000000000000000000000000000005f5260045ffd5b63f80dbaea5f526020526024601cfd5b949291909360a08201359261501b60c084018461312c565b919061502a606083018361312c565b615035859295612b5b565b945f90838310838518028418925f915b8483106150ea575050506115f0575b8181106150ca5750505090604061506e93920135906149ef565b9061508e8284670de0b6b3a7640000808084118184111493149114171790565b156115f0576150be946150ad6150c493614aba95608085013591614a52565b818098856060849895970190613180565b90614af6565b96614b81565b806150d860019284866132d5565b356150e38288612b47565b5201615054565b9091926150f88487896132d5565b35937dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8516946151278286866132d5565b35956151338782612bda565b967ffffffffffffffffffffffffffffffffffffffffffffffffff21f494c589c00008801978811611fbb576001946151c07dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff927fffff00000000000000000000000000000000000000000000000000000000000094670de0b6b3a7640000808084118184111493149114171790565b15828a11171797169116176151d5828c612b47565b52019190615045565b60806151f3612dc161322f606085018561312c565b519020916040519260208401947fe829b2a82439f37ac7578a226e337d334e0ee0da2f05ab63891c19cb84714414865260408501526020820135606085015260408201358385015260a0840152013560c082015260c08152612efe60e08261252a565b7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000046186152a15790565b5060a06040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f0e2a7404936dd29a4a3b49dad6c2f86f8e2da9cf7cf60ef9518bb049b4cb9b4460208201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660408201524660608201523060808201522090565b9190915f9173ffffffffffffffffffffffffffffffffffffffff8216156154445760405192600484019460248501956044860192853b156153ae57509286928695926020957f1626ba7e00000000000000000000000000000000000000000000000000000000809952526040845281518501809260045afa9360443d01915afa169151141690565b979650509050815180604014615405576041146153cb5750505050565b60209293955060608201515f1a835260408201516060525b5f5201516040526020600160805f825afa511860601b3d11915f606052604052565b506020929395507f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6040830151601b8160ff1c018552166060526153e3565b505050505f90565b90915f5b6060830161545e8185613180565b9050821015615544578161086b6154759286613180565b906154808186612b47565b519173ffffffffffffffffffffffffffffffffffffffff6154a08261310b565b166154c2576001926154b760406154bc930161310b565b6149d3565b01615450565b6154d760406154d08361310b565b920161310b565b604051936060526040523360601b602c526f23b872dd000000000000000000000000600c5260205f6064601c82855af1908160015f51141615615526575b50506001915f6060526040526154bc565b3b153d171015615537575f80615515565b637939f4245f526004601cfd5b5050915050565b92909160e0840161555c818661312c565b905015158061573c575b615572575b5050505050565b615588615582615593928761312c565b90612c3b565b946060810190613180565b91909115612b1a575f60209461568e73ffffffffffffffffffffffffffffffffffffffff976155d86155d28a6155cb60408a0161310b565b169761310b565b97612b0d565b516155e589830183612c74565b9060406156576155f86060860186612ca7565b94909383519e8f9d8e9c8d9b7f63f3660b000000000000000000000000000000000000000000000000000000008d528c60048c3591015260248d015260448c01521660648a0152608489015261010060a489015261010488019061405c565b93013560c48601527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8584030160e4860152612cf8565b03925af1908115614388577f63f3660b00000000000000000000000000000000000000000000000000000000917fffffffff00000000000000000000000000000000000000000000000000000000915f9161571d575b5016036156f5575f8080808061556b565b7fe012030f000000000000000000000000000000000000000000000000000000005f5260045ffd5b615736915060203d60201161438157614373818361252a565b5f6156e4565b5061574a6060860186613180565b90501515615566565b91906370a082315f5230602052602060346024601c865afa601f3d1116156157c157601452603451916fa9059cbb0000000000000000000000005f5260205f6044601082855af1908160015f511416156157b0575b50505f603452565b3b153d1710156157c1575f806157a8565b6390b8ec185f526004601cfd5b604051906157db826124f2565b60606040835f81525f6020820152015256fea164736f6c634300081e000a

Deployed Bytecode

0x6080604052600436101561001a575b3615610018575f80fd5b005b5f5f3560e01c806306fdde03146124055780630e71a7bf146120c7578063132e3a2314611e265780631e2eaeaf14611dec57806321eaf4cc14611c66578063288cdc9114611c1f5780633540346214611b9957806342b16dd714611b295780634c73f1d214611acf578063533e1aef14611a5657806353e09f0f146119fc578063542c0792146119bc57806356d5b3e014611958578063595be4491461193f5780635e7ef41d1461177c57806373e37b23146116945780637f8f3ea61461161857806380008e37146114d7578063a2cc82f514611329578063dbd035ff14611293578063e2a17a5714611092578063e84dded61461104d578063ee75775e14610f69578063ef74074f14610e13578063f0b6dce414610db15763f71b182814610143575061000e565b60c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af3576004359067ffffffffffffffff8211610af35760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8336030112610af35767ffffffffffffffff60243511610af3576101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60243536030112610af35767ffffffffffffffff60443511610af35760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60443536030112610af35760643567ffffffffffffffff8111610af35761024b9036906004016126c8565b7f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c09291925c610da4576102c56102f491337f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d6102a960a435614642565b94856004604435016102ba8161310b565b602435600401614e56565b926102e06102d66004870180612c74565b6080810190612be7565b906044356004019160243560040191615003565b9491936103046004840180612c74565b906103156024850185600401612ca7565b9490956103286044830183600401612ca7565b9760405197610100890189811067ffffffffffffffff821117610af75761039d936103949160409e9d9e5260608b52606060208c01525f60408c01525f60608c01525f60808c01525f60a08c0152606060c08c0152606060e08c015261038c6157ce565b9b3691614682565b89523691614682565b602087015273ffffffffffffffffffffffffffffffffffffffff6103c36020860161310b565b16604087015260408401356060870152606084013560808701528260a08701526103eb6127f1565b60c087015284517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061043561041f8361256b565b9261042d604051948561252a565b80845261256b565b015f5b818110610d8757505060e08701526040985f5b8651811015610597577fffffffffffffffffffffffff000000000000000000000000000000000000000061049461048f8361048960808b018b612be7565b90612bca565b6132f2565b1673ffffffffffffffffffffffffffffffffffffffff6104c660206104c08561048960808d018d612be7565b0161310b565b161789528a6104dc8261048960808a018a612be7565b013560208a01528a516104ef8c8261252a565b600181525f5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08d0181106105755750908160019260408c015261053560843591612b0d565b51526105418189612b47565b51602061055160408d0151612b0d565b51015261056e8160e08b01518c6105688383612b47565b52612b47565b500161044b565b6020908d516105838161250e565b5f81525f83820152828285010152016104f5565b50899087878b886105a78161310b565b3073ffffffffffffffffffffffffffffffffffffffff821614610d73575b865180957f6428cb590000000000000000000000000000000000000000000000000000000082526020600483015260e06106b96106476106138451610100602488015261012487019061247e565b60208501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc87830301604488015261247e565b73ffffffffffffffffffffffffffffffffffffffff604085015116606486015260608401516084860152608084015160a486015260a084015160c486015260c08401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc8683030160e487015261247e565b910151907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc83820301610104840152815180825260208201916020808360051b8301019401925f915b8d848410610cd45750505050505091815f73ffffffffffffffffffffffffffffffffffffffff826020960393165af1938415610c2b575f94610ca0575b50610754606460243501602435600401613180565b9050610990575b50670de0b6b3a7640000811061097e575b506107da61077e60443560040161310b565b6107b6610790856044356004016151de565b610798615256565b90919091604051926119015f526020526040526042601e2091604052565b6107d46107cd60a460443501604435600401612ca7565b3691614682565b91615326565b15610956576107ee8360243560040161544c565b61080c610805606460243501602435600401613180565b90506146e6565b94805b610823606460243501602435600401613180565b90508110156108a1578061083960019287612b47565b5173ffffffffffffffffffffffffffffffffffffffff610871896104c08561086b606460243501602435600401613180565b90612ff2565b89519261087d8461250e565b835216602082015261088f828a612b47565b5261089a8189612b47565b500161080f565b5090939195946108c060206104c0610952988060040190600401612c74565b907fe2158b757579e39997b81ac181c3fd651ef57041e5da67df952949106a0ea4e78451806109128b8a73ffffffffffffffffffffffffffffffffffffffff608435981696604480350135928561475e565b0390a361092683888860243560040161554b565b7f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d519485948561279d565b0390f35b6004857f79f9cc43000000000000000000000000000000000000000000000000000000008152fd5b8286526001602052848620558761076c565b96929095916109ad606460249a96979a3501602435600401613180565b9790507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06109f26109dd8a61256b565b996109ea8d519b8c61252a565b808b5261256b565b015f5b818110610c785750505f5b610a14606460243501602435600401613180565b9050811015610b2457610a358161086b606460243501602435600401613180565b90608082360312610af3578b5191608083019280841067ffffffffffffffff851117610af7578d9384526060610a6a836127d0565b92838352602081013595866020850152610a858183016127d0565b908401520135938415158503610af35773ffffffffffffffffffffffffffffffffffffffff8f92858e6001986060610abe940152612b47565b51925193610acb856124f2565b16835260208301528d820152610ae1828c612b47565b52610aec818b612b47565b5001610a00565b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b50919397610b3e9099969599979193976080810190612be7565b9190333b15610af3579190610bbe610b8e89519485947fdc5620dc000000000000000000000000000000000000000000000000000000008652896004870152608060248701526084860191613fcd565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc848203016044850152866125e0565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc838203016064840152602080835192838152019201905f5b818110610c355750505090805f92038183335af18015610c2b571561075b57610c239196505f9061252a565b5f948861075b565b86513d5f823e3d90fd5b8251805173ffffffffffffffffffffffffffffffffffffffff16855260208181015181870152908c01518c86015286955060609094019390920191600101610bf7565b6020908c5f815191610c89836124f2565b818352818584015282015282828d010152016109f5565b9093506020813d602011610ccc575b81610cbc6020938361252a565b81010312610af35751928961073f565b3d9150610caf565b509193955091937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08282030183528c8651602060808360608601938051875283810151848801520151946060858201528551809452019301915f905b828210610d53575050505060208060019297019301930190928a95949293610702565b83518051865260209081015181870152940193909201916001018f610d30565b506c171ede64904551eedf3c6c97886105c5565b602090610d959c9b9c6157ce565b828286010152019a999a610438565b638beb9d165f526004601cfd5b34610af35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043567ffffffffffffffff8111610af357610e0b610e0560209236906004016126c8565b90613c13565b604051908152f35b60a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760243567ffffffffffffffff8111610af35760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8236030112610af3576064359073ffffffffffffffffffffffffffffffffffffffff82168203610af3576084359067ffffffffffffffff8211610af35736602383011215610af35781600401359067ffffffffffffffff8211610af3573660248385010111610af3577f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05c610da4576020936024610f3e94337f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d019160443590600401600435613378565b5f7f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d604051908152f35b34610af35760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043573ffffffffffffffffffffffffffffffffffffffff811690818103610af357506044359073ffffffffffffffffffffffffffffffffffffffff821691828103610af3575060643591821515808403610af3576020935060405191848301937f97a135285706d21a6b74ac159b77b16cea827acc358fc6c33e430ce0a85fe9d6855260408401526024356060840152608083015260a082015260a0815261104260c08261252a565b519020604051908152f35b34610af3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760206040516c171ede64904551eedf3c6c97888152f35b60e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043567ffffffffffffffff8111610af35760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc826004019236030112610af3576024359067ffffffffffffffff8211610af3576101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8336030112610af35760443567ffffffffffffffff8111610af35760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8236030112610af35760643567ffffffffffffffff8111610af35761119c9036906004016126c8565b9390916084359160c4359567ffffffffffffffff8711610af35760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8836030112610af3577f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05c610da45761095294611264938561125194337f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d61124360a435614642565b92600401906004018a6147db565b9483838793969599949a6004019461411f565b5f7f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d6040519485948561279d565b34610af35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043567ffffffffffffffff8111610af3576112e29036906004016126c8565b6040519160408360208152836020820152019160051b83019060206040830191935b8435548152019284828510156113205750602080910193611304565b60408185030190f35b34610af35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043567ffffffffffffffff8111610af3576113789036906004016126c8565b906113828261256b565b91611390604051938461252a565b8083527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06113bd8261256b565b015f5b8181106114b45750505f5b81811061142357836040518091602082016020835281518091526020604084019201905f5b8181106113fe575050500390f35b82518051855260209081015181860152869550604090940193909201916001016113f0565b8061143160019284866132d5565b35805f525f60205261148460405f2054915f52600160205260405f20547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff670de0b6b3a764000082150282179114150290565b604051916114918361250e565b825260208201526114a28287612b47565b526114ad8186612b47565b50016113cb565b6020906040516114c38161250e565b5f81525f83820152828288010152016113c0565b34610af35760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043567ffffffffffffffff8111610af3576115269036906004016124c1565b9060243567ffffffffffffffff8111610af3576115479036906004016126f9565b9060443567ffffffffffffffff8111610af357611568903690600401612583565b9061157d60c4359260843590606435906149ef565b9261159d8484670de0b6b3a7640000808084118184111493149114171790565b156115f0576115e2956115c86115bd610952966115ce9660a43591614a52565b949080948692614af6565b95614b81565b6040519384936040855260408501906125e0565b9083820360208501526125e0565b7fe80f2482000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610af35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043567ffffffffffffffff8111610af3576101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8236030112610af357610e0b602091600401613208565b34610af35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043567ffffffffffffffff8111610af357806004019060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8236030112610af357611722610e0583602461171a60209661310b565b94019061312c565b6040519073ffffffffffffffffffffffffffffffffffffffff848301937fd98eceb6e5c7770b3b664a99c269855402fe5255294a30970d25376caea662c6855216604083015260608201526060815261104260808261252a565b60c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043567ffffffffffffffff8111610af35760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8236030112610af35760243567ffffffffffffffff8111610af3576101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8236030112610af3576044359167ffffffffffffffff8311610af35760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8436030112610af35760643567ffffffffffffffff8111610af3576118829036906004016126c8565b917f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05c610da457610952946118f494337f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d6118df60a435614642565b926084359260040191600401906004016147db565b90939193478061192f575b505f7f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d6040519485948561279d565b61193990336149d3565b856118ff565b34610af3576020610e0b6119523661272a565b906144ae565b34610af3576119663661272a565b907f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05c610da457602091610f3e91337f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d614393565b34610af3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af3576020604051670de0b6b3a76400008152f35b34610af35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043567ffffffffffffffff8111610af357610e0b611a5060209236906004016126f9565b9061302f565b34610af35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af3576020610e0b6004355f52600160205260405f20547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff670de0b6b3a764000082150282179114150290565b34610af35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043567ffffffffffffffff8111610af357610e0b611b2360209236906004016126c8565b90612d36565b34610af3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760207f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05c73ffffffffffffffffffffffffffffffffffffffff60405191168152f35b611ba236612613565b91907f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05c610da457602092610f3e91337f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d611bfe8185614393565b9384611c17611c106080840184612be7565b9050612b5b565b92339261411f565b34610af35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af3576004355f525f602052602060405f2054604051908152f35b611c6f36612613565b7f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05c610da457337f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d611cc282846144ae565b90815f525f60205260405f2054938415611dc457611d1c835f52600160205260405f20547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff670de0b6b3a764000082150282179114150290565b926080820192611d2f611c108585612be7565b965f5b88611d3d8787612be7565b9050821015611d76575080611d65886040611d5e6001956104898c8c612be7565b0135613f1a565b611d6f828c612b47565b5201611d32565b84611d85858386848e8c61411f565b5f7f929eee149b4bd21268e1321c4622803b452e74fd69be78111fba0332fa0fd4c05d61095260405192839283526040602084015260408301906125e0565b7fe0d88415000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610af35760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af357600435545f5260205ff35b34610af35760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35760043567ffffffffffffffff8111610af357611e759036906004016124c1565b9060243567ffffffffffffffff8111610af357611e96903690600401612583565b608435929060c43590604435606435670de0b6b3a7640000821561209357508082116120655790611ec992910390613c94565b935b611eea8583670de0b6b3a7640000808084118184111493149114171790565b156115f057611efa60a435613ed6565b611f0384612b5b565b95670de0b6b3a7640000841480612053575b670de0b6b3a764000085111715611fe8577ffffffffffffffffffffffffffffffffffffffffffffffffff21f494c589c00008401938411611fbb57611f60611f6692611f6c95612bb7565b90612bda565b90613f68565b915f5b8451811015611f9b57806040611f886001938686612bca565b0135611f948288612b47565b5201611f6f565b5050505b61095260405192839283526040602084015260408301906125e0565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b90919392670de0b6b3a764000003670de0b6b3a76400008111611fbb576120189261201291612bb7565b90612baa565b91925f5b855181101561204a5780612039856040611d5e6001958888612bca565b6120438289612b47565b520161201c565b50505050611f9f565b50670de0b6b3a7640000811015611f15565b7f97417ef2000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b96929150505115611ecb575b7f97206b56000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610af3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af3576020612190600160286121066127f1565b6040519485917f4d616e6461746528000000000000000000000000000000000000000000000000828401528051918291018484015e81017f29000000000000000000000000000000000000000000000000000000000000008382015203017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181018452018261252a565b604080519061219f818361252a565b600182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015f5b8181106123db5761232785858580516121e0816124f2565b81516121ec838261252a565b601e81527f66696c6c735b5d2e636f6d706f6e656e74735b5d2e66696c6c546f6b656e000060208201528152606090825161222860608261252a565b602681527f66696c6c735b5d2e636f6d706f6e656e74735b5d2e6d696e696d756d46696c6c60208201527f416d6f756e740000000000000000000000000000000000000000000000000000848201526020820152825161228960808261252a565b604a81527f4f757470757420746f6b656e20616e64206d696e696d756d20616d6f756e742060208201527f666f7220656163682066696c6c20636f6d706f6e656e7420696e207468652046848201527f696c6c732061727261790000000000000000000000000000000000000000000060608201528382015261230b84612b0d565b5261231583612b0d565b5081519485948386528386019061247e565b848103602086015283519182825260208201906020808560051b8501019601945f935b8585106123575788880389f35b91939597509193956020806123c7837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe086600196030189528b5190876123b76123a784518c85528c85019061247e565b868501518482038886015261247e565b920151908881840391015261247e565b99019501950192909188979694959261234a565b60209083516123e9816124f2565b60608152606083820152606085820152828287010152016121c8565b34610af3575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610af35761095260405161244460408261252a565b600881527f54726962756e616c00000000000000000000000000000000000000000000000060208201526040519182916020835260208301905b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b9181601f84011215610af35782359167ffffffffffffffff8311610af35760208085019460608502010111610af357565b6060810190811067ffffffffffffffff821117610af757604052565b6040810190811067ffffffffffffffff821117610af757604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610af757604052565b67ffffffffffffffff8111610af75760051b60200190565b9080601f83011215610af357813561259a8161256b565b926125a8604051948561252a565b81845260208085019260051b820101928311610af357602001905b8282106125d05750505090565b81358152602091820191016125c3565b90602080835192838152019201905f5b8181106125fd5750505090565b82518452602093840193909201916001016125f0565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc820112610af35760043567ffffffffffffffff8111610af35760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8284030112610af35760040191602435916044359067ffffffffffffffff8211610af3577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82608092030112610af35760040190565b9181601f84011215610af35782359167ffffffffffffffff8311610af3576020808501948460051b010111610af357565b9181601f84011215610af35782359167ffffffffffffffff8311610af3576020808501948460071b010111610af357565b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc820112610af3576004359067ffffffffffffffff8211610af3577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8260a092030112610af3576004019060243590565b926127cd94926127bf92855260208501526080604085015260808401906125e0565b9160608184039101526125e0565b90565b359073ffffffffffffffffffffffffffffffffffffffff82168203610af357565b604051906128016102a08361252a565b61027b82527f6d7061637420636f6d706163742c627974657320636f6e746578740000000000610280837f616464726573732061646a75737465722c4d616e646174655f46696c6c5b5d2060208201527f66696c6c73294d616e646174655f4261746368436f6d7061637428616464726560408201527f737320617262697465722c616464726573732073706f6e736f722c75696e743260608201527f3536206e6f6e63652c75696e7432353620657870697265732c4d616e6461746560808201527f5f4c6f636b5b5d20636f6d6d69746d656e74732c4d616e64617465206d616e6460a08201527f617465294d616e646174655f46696c6c2875696e7432353620636861696e496460c08201527f2c616464726573732074726962756e616c2c75696e743235362065787069726560e08201527f732c4d616e646174655f46696c6c436f6d706f6e656e745b5d20636f6d706f6e6101008201527f656e74732c75696e7432353620626173656c696e655072696f726974794665656101208201527f2c75696e74323536207363616c696e67466163746f722c75696e743235365b5d6101408201527f20707269636543757276652c4d616e646174655f526563697069656e7443616c6101608201527f6c6261636b5b5d20726563697069656e7443616c6c6261636b2c6279746573336101808201527f322073616c74294d616e646174655f46696c6c436f6d706f6e656e74286164646101a08201527f726573732066696c6c546f6b656e2c75696e74323536206d696e696d756d46696101c08201527f6c6c416d6f756e742c6164647265737320726563697069656e742c626f6f6c206101e08201527f6170706c795363616c696e67294d616e646174655f4c6f636b286279746573316102008201527f32206c6f636b5461672c6164647265737320746f6b656e2c75696e74323536206102208201527f616d6f756e74294d616e646174655f526563697069656e7443616c6c6261636b6102408201527f2875696e7432353620636861696e49642c4d616e646174655f4261746368436f6102608201520152565b805115612b1a5760200190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b8051821015612b1a5760209160051b010190565b90612b658261256b565b612b72604051918261252a565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0612ba0829461256b565b0190602036910137565b91908203918211611fbb57565b81810292918115918404141715611fbb57565b9190811015612b1a576060020190565b91908201809211611fbb57565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610af3570180359067ffffffffffffffff8211610af357602001916060820236038313610af357565b9015612b1a578035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8181360301821215610af3570190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6181360301821215610af3570190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610af3570180359067ffffffffffffffff8211610af357602001918136038313610af357565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b9080612d625750507fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47090565b60018103612fca57612d7391612c3b565b612d806020820182612c74565b612d8d6080820182612be7565b90612d9782612b5b565b915f5b818110612f0457505050612dc191612ee291604051612ded81612dc1602082018095613002565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0810183528261252a565b51902090612dfa8161310b565b916060612e096020840161310b565b9273ffffffffffffffffffffffffffffffffffffffff604051948160208701977f75d7205b7ec9e9b203d9161387d95a46c8440f4530dceab1bb28d4194a5862278952166040870152168285015260408101356080850152013560a083015260c0820152604085013560e082015260e08152612e876101008261252a565b519020612e976060850185612ca7565b939060405194859360208501977fb60a17eb6828a433f2f2fcbeb119166fa25e1fb6ae3866e33952bb74f50550318952356040860152606085015260808085015260a0840191612cf8565b5190206040516020810191825260208152612efe60408261252a565b51902090565b80612f1561048f6001938587612bca565b612f2560206104c0848789612bca565b6040612f32848789612bca565b013573ffffffffffffffffffffffffffffffffffffffff604051927fffffffffffffffffffffffff000000000000000000000000000000000000000060208501957fce4f0854d9091f37d9dfb64592eee0de534c6680a5444fd55739b61228a6e0b08752166040850152166060830152608082015260808152612fb660a08261252a565b519020612fc38287612b47565b5201612d9a565b7fa3cb8f80000000000000000000000000000000000000000000000000000000005f5260045ffd5b9190811015612b1a5760071b0190565b80516020909101905f5b8181106130195750505090565b825184526020938401939092019160010161300c565b61303882612b5b565b915f5b81811061305a57505050604051612efe81612dc1602082018095613002565b806130686001928486612ff2565b6130718161310b565b9061307e6040820161310b565b73ffffffffffffffffffffffffffffffffffffffff61309f606084016132e5565b9160206040519483828701977f97a135285706d21a6b74ac159b77b16cea827acc358fc6c33e430ce0a85fe9d6895216604087015201356060850152166080830152151560a082015260a081526130f760c08261252a565b5190206131048287612b47565b520161303b565b3573ffffffffffffffffffffffffffffffffffffffff81168103610af35790565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610af3570180359067ffffffffffffffff8211610af357602001918160051b36038313610af357565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610af3570180359067ffffffffffffffff8211610af357602001918160071b36038313610af357565b91907f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8111610af35760051b809282370190565b613218611a506060830183613180565b90610100613243612dc161322f60c085018561312c565b9290604051928391602083019586916131d4565b51902091613257611b2360e083018361312c565b6040519360208501957f1d0ee69a7bc1ac54d9a6b38f32ab156fbfe09a9098843d54f89e7b1033533d3387524660408701523060608701526040840135608087015260a0860152608083013560c086015260a083013560e08601528385015261012084015201356101408201526101408152612efe6101608261252a565b9190811015612b1a5760051b0190565b358015158103610af35790565b357fffffffffffffffffffffffff000000000000000000000000000000000000000081168103610af35790565b90602080835192838152019201905f5b81811061333c5750505090565b909192835181905f915b600283106133625750505060400192602001919060010161332f565b6020806001928451815201920192019190613346565b90929593959491946080840160016133908287612be7565b905003613beb576133a19085612be7565b90929015612b1a575f525f60205260405f205480613b7057506133c66020850161310b565b811502187fffffffffffffffffffffffff00000000000000000000000000000000000000006133f4836132f2565b1615613b1b5760409283519261340a858561252a565b600184527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe085015f5b818110613afc5750505f9060207fffffffffffffffffffffffff000000000000000000000000000000000000000061346a836132f2565b1691019073ffffffffffffffffffffffffffffffffffffffff61348c8361310b565b161761349786612b0d565b515273ffffffffffffffffffffffffffffffffffffffff6134b78261310b565b1661394e57505047918260206134cc86612b0d565b5101525b871561388b575084840135806137f257506134ea83612b0d565b5151978451987f5b15bfd9000000000000000000000000000000000000000000000000000000008a5260048a015260a0896024816c171ede64904551eedf3c6c97885afa9283156137e85788995f99989994613756575b5061354e6020880161310b565b6135578861310b565b90848489519d8e947f7ef6597a00000000000000000000000000000000000000000000000000000000865260608d0135908b600488019661359797614d19565b038a73ffffffffffffffffffffffffffffffffffffffff861691815a6020945f91f18015610c2b5788999a5f9997989991613721575b506135da60208a0161310b565b906135e48a61310b565b89517fe9626d0c0000000000000000000000000000000000000000000000000000000081529b8c9384936136239360608f0135928c9060048801614c86565b03815a936c171ede64904551eedf3c6c97885f95f1978815610c2b575f986136fc575b506136536020880161310b565b9461365d8861310b565b9773ffffffffffffffffffffffffffffffffffffffff85163b15610af3576136d46060945f989473ffffffffffffffffffffffffffffffffffffffff948a968c519d8e9b8c9a8b987f89336227000000000000000000000000000000000000000000000000000000008a5201359260048901614d19565b0393165af19081156136f357506136e9575090565b5f6127cd9161252a565b513d5f823e3d90fd5b6137199198503d805f833e613711818361252a565b810190614c04565b50965f613646565b9650506020863d60201161374e575b8161373d6020938361252a565b81010312610af3578895515f6135cd565b3d9150613730565b9750925060a0873d60a0116137e0575b8161377360a0938361252a565b81010312610af35761378487614cf8565b5061379160208801614cf8565b966008868201511015610af357600260608201511015610af357608001517fffffffffffffffffffffffff0000000000000000000000000000000000000000811603610af3578896925f613541565b3d9150613766565b85513d5f823e3d90fd5b959750509091948361384f60609261380d60205f980161310b565b6138168461310b565b988a51998a98899788977fe9626d0c00000000000000000000000000000000000000000000000000000000895201359360048801614c86565b03916c171ede64904551eedf3c6c97885af19182156136f357505f91613873575090565b61388791503d805f833e613711818361252a565b5090565b9650509082949650602093506138ec9073ffffffffffffffffffffffffffffffffffffffff9351968794859384937f456b7d0c000000000000000000000000000000000000000000000000000000008552896004860152604485019061331f565b9116602483015203916c171ede64904551eedf3c6c97885af19081156136f3575061391657505f90565b6020813d602011613946575b8161392f6020938361252a565b81010312610af357518015158103610af357505f90565b3d9150613922565b602080602460106139618598969861310b565b306014526f70a082310000000000000000000000005f525afa601f3d111660205102602061398e87612b0d565b510152602080604460106139a18561310b565b306014526c171ede64904551eedf3c6c97886034526fdd62ed3e0000000000000000000000005f525afa601f3d1116602051025f60345260206139e387612b0d565b510151116139f2575b506134d0565b6139fb9061310b565b6c171ede64904551eedf3c6c97886014527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6034526f095ea7b30000000000000000000000005f5260205f6044601082855af18060015f51141615613a67575b50505f6034525f6139ec565b3d823b15171015613a79575b80613a5b565b5f6034526f095ea7b30000000000000000000000005f525f386044601083855af1507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60345260205f6044601082855af1908160015f51141615613ade575b50613a73565b3b153d171015613aef575f80613ad8565b633e3f8f735f526004601cfd5b6020908751613b0b898261252a565b8836823782828901015201613433565b94509150506020919350019073ffffffffffffffffffffffffffffffffffffffff613b458361310b565b16613b5a57613b56915047906149d3565b5f90565b613b66613b6b9261310b565b615753565b505f90565b9550509150506020919350019073ffffffffffffffffffffffffffffffffffffffff613b9b8361310b565b16613bc257613b56915073ffffffffffffffffffffffffffffffffffffffff4791166149d3565b73ffffffffffffffffffffffffffffffffffffffff613be3613b6b9361310b565b911690615753565b7f02492d60000000000000000000000000000000000000000000000000000000005f5260045ffd5b91613c1d82612b5b565b905f5b83811015613c7a578060051b850135907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee186360301821215610af357613c696001928701613208565b613c738286612b47565b5201613c20565b5092509050604051612efe81612dc1602082018095613002565b9091815115613ec7575f9081805b8451841015613e8f57613cb58486612b47565b51907dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260f01c92168215613e6457613cec8383612bda565b8810613d085750600191613cff91612bda565b935b0192613ca2565b9396928096929695919590613e25575b15613db2577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908111611fbb57613d5091612b47565b517dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1692670de0b6b3a76400008085148185141781861191851191909114175b156115f057613da06127cd9582612bda565b92670de0b6b3a7640000851194614d95565b92939260018101908110611fbb578151811015613e1457613dd291612b47565b517dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16915b613d8e8385670de0b6b3a7640000808084118184111493149114171790565b5050670de0b6b3a764000091613df5565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818111611fbb57613e5a9083612b47565b5160f01c15613d18565b9080959250871015613e7a575b50600190613d01565b60019250848703613e71579450505092505090565b9350509290501015613e9f575f90565b7f89cc9952000000000000000000000000000000000000000000000000000000005f5260045ffd5b915050670de0b6b3a764000090565b483a10613ef257483a0381811115613eec570390565b50505f90565b7ff3eb44e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211613f54575b670de0b6b3a764000091020490565b8015613f45575b63bac65e5b5f526004601cfd5b908082029181830403613f8b575b50670de0b6b3a7640000808204910615150190565b613f5b575f613f76565b90816020910312610af357517fffffffff0000000000000000000000000000000000000000000000000000000081168103610af35790565b916020908281520191905f905b808210613fe75750505090565b9091928335907fffffffffffffffffffffffff00000000000000000000000000000000000000008216809203610af35760608160019382935273ffffffffffffffffffffffffffffffffffffffff614041602089016127d0565b16602082015260408701356040820152019401920190613fda565b73ffffffffffffffffffffffffffffffffffffffff61407a826127d0565b16825273ffffffffffffffffffffffffffffffffffffffff61409e602083016127d0565b166020830152604081013560408301526060810135606083015260808101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe182360301811215610af357016020813591019067ffffffffffffffff8111610af3576060810236038213610af35760a0838160806127cd9601520191613fcd565b91929490938561416b855f52600160205260405f20547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff670de0b6b3a764000082150282179114150290565b92602081019461417a8661310b565b73ffffffffffffffffffffffffffffffffffffffff16938235988991606085016141a49086612ca7565b919092604051998a98899788977f401722d4000000000000000000000000000000000000000000000000000000008952600489015260248801610100905261010488016141f09161405c565b9260448801528d6064880152608487015260a48601528481037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0160c4860152614239916125e0565b908382037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0160e485015261426d92612cf8565b0391604001355a94602095f1908115614388577f401722d400000000000000000000000000000000000000000000000000000000917fffffffff00000000000000000000000000000000000000000000000000000000915f91614359575b50160361433157602073ffffffffffffffffffffffffffffffffffffffff6143137f6d55a93a63f6b120c85df7abd40f86808b20899b13ee33928427bb8827727e669361310b565b1692604051908152a447806143255750565b61432f90336149d3565b565b7ff0a08c77000000000000000000000000000000000000000000000000000000005f5260045ffd5b61437b915060203d602011614381575b614373818361252a565b810190613f95565b5f6142cb565b503d614369565b6040513d5f823e3d90fd5b602081019173ffffffffffffffffffffffffffffffffffffffff6143b68461310b565b163303614486576143c6916144ae565b90815f525f60205260405f205461445e5761443073ffffffffffffffffffffffffffffffffffffffff91835f525f6020523360405f2055835f5260016020527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60405f205561310b565b167fdb2b33dd6349739e1f3cd6dc90cf093af6a3dfb1838aced380528b0aefe6093c6020604051848152a290565b7f41a26a63000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fdf4795c7000000000000000000000000000000000000000000000000000000005f5260045ffd5b6144bb6080820182612be7565b906144c582612b5b565b915f5b81811061457c575050506040516144e781612dc1602082018095613002565b519020916144f48261310b565b9260606145036020850161310b565b9373ffffffffffffffffffffffffffffffffffffffff604051958160208801987fdbbdcf42471b4a26f7824df9f33f0a4f9bb4e7a66be6a31be8868a6cbbec0a7d8a52166040880152168286015260408101356080860152013560a084015260c083015260e082015260e08152612efe6101008261252a565b8061458d61048f6001938587612bca565b61459d60206104c0848789612bca565b60406145aa848789612bca565b013573ffffffffffffffffffffffffffffffffffffffff604051927fffffffffffffffffffffffff000000000000000000000000000000000000000060208501957ffb7744571d97aa61eb9c2bc3c67b9b1ba047ac9e95afb2ef02bc5b3d9e64fbe5875216604085015216606083015260808201526080815261462e60a08261252a565b51902061463b8287612b47565b52016144c8565b9061464b614dd9565b91828115021891820361465a57565b7f5345d2f0000000000000000000000000000000000000000000000000000000005f5260045ffd5b92919267ffffffffffffffff8211610af757604051916146ca601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0166020018461252a565b829481845281830111610af3578281602093845f960137010152565b906146f08261256b565b6146fd604051918261252a565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061472b829461256b565b01905f5b82811061473b57505050565b60209060405161474a8161250e565b5f81525f838201528282850101520161472f565b9493929060808601908652608060208701528251809152602060a087019301905f5b8181106147a3575050508161479e91866060940360408801526125e0565b930152565b82518051865260209081015173ffffffffffffffffffffffffffffffffffffffff168187015260409095019490920191600101614780565b9461480f91949297966147f991848a6147f38161310b565b89614e56565b9187856148096080890189612be7565b90615003565b929193909687908592614822858a6144ae565b95865f525f60205260405f205461445e57865f525f6020528160405f2055670de0b6b3a764000081106149c0575b5061487c61485d8c61310b565b8c6107d46107cd6148716107908c856151de565b9260a0810190612ca7565b15614998576148ae9a61488f888a61544c565b606089019a6148a16108058d8c613180565b9a8c5f9e8f915b8d613180565b9190501015614925576148ae60018e9f8f8f8f908f9173ffffffffffffffffffffffffffffffffffffffff6148fb60406104c08861086b61491a996148f483809b612b47565b5197613180565b604051926149088461250e565b83521660208201526105688383612b47565b50019e908f916148a8565b889d50879c507f79250a3d76a8bc9cbf78119657750fb9310acddd28a27c2df2691226108fd3c79161499061432f9a979c969b99989d61497c602073ffffffffffffffffffffffffffffffffffffffff950161310b565b926040805195869516970135918a8561475e565b0390a361554b565b7f79f9cc43000000000000000000000000000000000000000000000000000000005f5260045ffd5b865f52600160205260405f20555f614850565b5f80809338935af1156149e257565b63b12d13eb5f526004601cfd5b909291670de0b6b3a76400008415614a465750808411614a1657926127cd92930390613c94565b83907f97417ef2000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b929350505161209f5790565b909291614a5e90613ed6565b90670de0b6b3a7640000841480614ae4575b670de0b6b3a7640000851117938415614abe577ffffffffffffffffffffffffffffffffffffffffffffffffff21f494c589c00008101908111611fbb57614aba92611f6091612bb7565b9190565b670de0b6b3a764000003670de0b6b3a76400008111611fbb57614aba9261201291612bb7565b50670de0b6b3a7640000811015614a70565b929190614b0281612b5b565b935f5b828110614b1457505050505090565b80614b2d6060614b276001948787612ff2565b016132e5565b15614b62578515614b6257614b50856020614b49848888612ff2565b0135613f68565b614b5a8289612b47565b525b01614b05565b6020614b6f828686612ff2565b0135614b7b8289612b47565b52614b5c565b90939291614b8e85612b5b565b9215614bca57505f5b8251811015614bc357806040614bb06001938886612bca565b0135614bbc8286612b47565b5201614b97565b5090925050565b93905f5b8351811015614bfc5780614beb876040611d5e6001958888612bca565b614bf58287612b47565b5201614bce565b509193505050565b9190604083820312610af35782519260208101519067ffffffffffffffff8211610af357019080601f83011215610af3578151614c408161256b565b92614c4e604051948561252a565b81845260208085019260051b820101928311610af357602001905b828210614c765750505090565b8151815260209182019101614c69565b9296959491614cbd73ffffffffffffffffffffffffffffffffffffffff918260c0979416865260e0602087015260e086019061331f565b97166040840152606083015260808201527fdbbdcf42471b4a26f7824df9f33f0a4f9bb4e7a66be6a31be8868a6cbbec0a7d60a08201520152565b519073ffffffffffffffffffffffffffffffffffffffff82168203610af357565b92959390614d516127cd98969373ffffffffffffffffffffffffffffffffffffffff809316865260e0602087015260e086019061331f565b9616604084015260608301527fdbbdcf42471b4a26f7824df9f33f0a4f9bb4e7a66be6a31be8868a6cbbec0a7d608083015260a082015260c0818503910152612cf8565b9190949293858303614da957505050505090565b91614dc682611f6093614dcc969798950397039182880390612bb7565b92612bb7565b9181830304019015150290565b4661a4b103614e52576040517fa3b1b31d00000000000000000000000000000000000000000000000000000000815260208160048160645afa908115614388575f91614e23575090565b90506020813d602011614e4a575b81614e3e6020938361252a565b81010312610af3575190565b3d9150614e31565b4390565b9190949392604083013542811115614ff3575046833503614fcb5760808201359073ffffffffffffffffffffffffffffffffffffffff82169160a01c90614ea1826040860135612bda565b1115901515169073ffffffffffffffffffffffffffffffffffffffff3391338115021816141517614fa357602001359083821091821592614f82575b5050614f5a57614efc612dc191604051928391602083019586916131d4565b5190206040519073ffffffffffffffffffffffffffffffffffffffff60208301937fd98eceb6e5c7770b3b664a99c269855402fe5255294a30970d25376caea662c68552166040830152606082015260608152612efe60808261252a565b7f838a8d5f000000000000000000000000000000000000000000000000000000005f5260045ffd5b614f9a919250614f939085856132d5565b3591613208565b14155f80614edd565b7f6770cd44000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f7a47c9a2000000000000000000000000000000000000000000000000000000005f5260045ffd5b63f80dbaea5f526020526024601cfd5b949291909360a08201359261501b60c084018461312c565b919061502a606083018361312c565b615035859295612b5b565b945f90838310838518028418925f915b8483106150ea575050506115f0575b8181106150ca5750505090604061506e93920135906149ef565b9061508e8284670de0b6b3a7640000808084118184111493149114171790565b156115f0576150be946150ad6150c493614aba95608085013591614a52565b818098856060849895970190613180565b90614af6565b96614b81565b806150d860019284866132d5565b356150e38288612b47565b5201615054565b9091926150f88487896132d5565b35937dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8516946151278286866132d5565b35956151338782612bda565b967ffffffffffffffffffffffffffffffffffffffffffffffffff21f494c589c00008801978811611fbb576001946151c07dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff927fffff00000000000000000000000000000000000000000000000000000000000094670de0b6b3a7640000808084118184111493149114171790565b15828a11171797169116176151d5828c612b47565b52019190615045565b60806151f3612dc161322f606085018561312c565b519020916040519260208401947fe829b2a82439f37ac7578a226e337d334e0ee0da2f05ab63891c19cb84714414865260408501526020820135606085015260408201358385015260a0840152013560c082015260c08152612efe60e08261252a565b7f987ca206d97d9e1d89784380c694fe7d0ae94a7cdf8145f485169baa0e93680d7f000000000000000000000000000000000000000000000000000000000000a4b146186152a15790565b5060a06040517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f0e2a7404936dd29a4a3b49dad6c2f86f8e2da9cf7cf60ef9518bb049b4cb9b4460208201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660408201524660608201523060808201522090565b9190915f9173ffffffffffffffffffffffffffffffffffffffff8216156154445760405192600484019460248501956044860192853b156153ae57509286928695926020957f1626ba7e00000000000000000000000000000000000000000000000000000000809952526040845281518501809260045afa9360443d01915afa169151141690565b979650509050815180604014615405576041146153cb5750505050565b60209293955060608201515f1a835260408201516060525b5f5201516040526020600160805f825afa511860601b3d11915f606052604052565b506020929395507f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6040830151601b8160ff1c018552166060526153e3565b505050505f90565b90915f5b6060830161545e8185613180565b9050821015615544578161086b6154759286613180565b906154808186612b47565b519173ffffffffffffffffffffffffffffffffffffffff6154a08261310b565b166154c2576001926154b760406154bc930161310b565b6149d3565b01615450565b6154d760406154d08361310b565b920161310b565b604051936060526040523360601b602c526f23b872dd000000000000000000000000600c5260205f6064601c82855af1908160015f51141615615526575b50506001915f6060526040526154bc565b3b153d171015615537575f80615515565b637939f4245f526004601cfd5b5050915050565b92909160e0840161555c818661312c565b905015158061573c575b615572575b5050505050565b615588615582615593928761312c565b90612c3b565b946060810190613180565b91909115612b1a575f60209461568e73ffffffffffffffffffffffffffffffffffffffff976155d86155d28a6155cb60408a0161310b565b169761310b565b97612b0d565b516155e589830183612c74565b9060406156576155f86060860186612ca7565b94909383519e8f9d8e9c8d9b7f63f3660b000000000000000000000000000000000000000000000000000000008d528c60048c3591015260248d015260448c01521660648a0152608489015261010060a489015261010488019061405c565b93013560c48601527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8584030160e4860152612cf8565b03925af1908115614388577f63f3660b00000000000000000000000000000000000000000000000000000000917fffffffff00000000000000000000000000000000000000000000000000000000915f9161571d575b5016036156f5575f8080808061556b565b7fe012030f000000000000000000000000000000000000000000000000000000005f5260045ffd5b615736915060203d60201161438157614373818361252a565b5f6156e4565b5061574a6060860186613180565b90501515615566565b91906370a082315f5230602052602060346024601c865afa601f3d1116156157c157601452603451916fa9059cbb0000000000000000000000005f5260205f6044601082855af1908160015f511416156157b0575b50505f603452565b3b153d1710156157c1575f806157a8565b6390b8ec185f526004601cfd5b604051906157db826124f2565b60606040835f81525f6020820152015256fea164736f6c634300081e000a

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ 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.