Blockchain / Global / Address

Contract

0xF9633dC97b0bc8f37d3913D58F2CDf454A3bd5bD

Balance
0 SOMI
Transactions sent
1
Type
Contract · 32,962 bytes of code

OnChainEventMarket Verified

Compiler
solc 0.8.30+commit.73712a01
Language
Solidity
Optimization
Yes, 50 runs
EVM version
cancun
License
—
Verified
2026-10-12

contracts/OnChainEventMarket.sol

and 27 more files

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

import { IProphecyCore } from "./interfaces/IProphecyCore.sol";
import { IProphecySettlement } from "./interfaces/IProphecySettlement.sol";
import { SomniaEventHandler } from "./lib/SomniaEventHandler.sol";
import { ISomniaEventHandler, ISomniaReactivityPrecompile, SomniaExtensions } from "./interfaces/ISomniaReactivity.sol";
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import { Ownable2StepUpgradeable } from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import {
    Operator,
    LogicalOperator,
    ParamType,
    OccurrenceType,
    SingleCondition,
    ConditionInput,
    InternalCondition,
    ConditionGroup,
    MarketLocal,
    CreateMarketParams,
    CreateMarketParamsV2
} from "./types/OnChainEventTypes.sol";
import { ConditionEval } from "./lib/ConditionEval.sol";
import { ConditionBuilderLib } from "./lib/ConditionBuilderLib.sol";
import { OutcomeEvalLib } from "./lib/OutcomeEvalLib.sol";
import { MarketDataLib } from "./lib/MarketDataLib.sol";
import { LiquidityLib } from "./lib/LiquidityLib.sol";
import { VenuePermitLib } from "./lib/VenuePermitLib.sol";
import {
    IHttpSingletonSomniaAgents,
    IAgent,
    ConsensusType,
    ResponseStatus,
    AgentResponse,
    AgentRequest
} from "./interfaces/ISomniaAgents.sol";

error UntrustedResolverOverride();
error NotMarketResolver();
error ResolutionWindowNotOpen();
error MarketAlreadyResolved();
error NameGenAgentPlatformOnly();
error ZeroAddr();
error NoGroups();
error IncorrectMsgValue();
error ZeroEventAddress();
error ZeroEventTopic();

interface IProphecyCoreEventLookup {
    function marketEventId(
        uint256 marketId
    ) external view returns (uint256);
}

/**
 * @title On-Chain Event-Based Market Protocol
 * @notice This contract facilitates the creation and resolution of prediction markets based on verifiable on-chain events.
 * It integrates with a ProphecyCore contract for ledger and betting management,
 * and subscribes to on-chain events via the Somnia Reactivity Precompile.
 * @dev This contract acts as a "resolver" for the ProphecyCore system. It determines the outcome of a market
 * by listening to specific events and evaluating predefined conditions against the data emitted in those events.
 * Resolution follows a lazy model, where the ProphecyCore contract pulls the final outcome from this contract via the `outcomeFor` function
 * after the market's resolution window has passed.
 * The contract logic is centered around "Condition Groups", where each group is tied to a specific on-chain event.
 * A market's outcome is determined by the logical combination (AND/OR) of its associated Condition Groups.
 */
contract OnChainEventMarket is
    SomniaEventHandler,
    UUPSUpgradeable,
    Ownable2StepUpgradeable,
    ReentrancyGuardUpgradeable
{
    // --- Constants ---
    uint256 public constant MIN_SUBSCRIPTION_BALANCE = 50 ether;
    uint256 private constant _COST_BUFFER_BPS = 500; // 5% buffer on getCreateMarketCost
    uint256 internal constant _SCHEDULE_BATCH_SIZE = 10;
    uint256 internal constant _OVERFLOW_DELAY_SEC = 5;
    uint256 private constant _NAME_GEN_SUBCOMMITTEE_SIZE = 1;
    uint256 public constant NAME_GEN_AGENT_ID = 12847293847561029384;
    uint256 private constant _NAME_GEN_TIMEOUT = 5 minutes;

    // --- State ---
    /// @notice The core ProphecyCore contract interface for market registration and resolution.
    IProphecyCore public prophecyCore;
    ISomniaReactivityPrecompile internal _reactivityPrecompile;

    mapping(bytes32 => uint64) internal _subscriptionIds;

    // Schedules for starting and ending market event subscriptions.
    mapping(uint256 => uint64) internal _resolutionStartScheduleSubIds; // marketId -> schedule sub id (start)
    mapping(uint256 => uint256[]) internal _marketsToSubscribeByTimestampSec; // timestamp (s) -> marketIds to activate
    mapping(uint256 => uint256[]) internal _marketsToUnsubscribeByTimestampSec; // timestamp (s) -> marketIds to deactivate
    mapping(uint256 => uint256) internal _marketToResolutionStartTimestampSec; // marketId -> start schedule ts (s)
    mapping(uint256 => uint256) internal _marketToResolutionEndTimestampSec; // marketId -> end schedule ts (s)
    mapping(bytes32 => uint256[]) internal _eventSubscribers; // shared subscriber registry
    mapping(bytes32 => uint256) internal _activeSubscriptionCounts; // active listener count per (source, topic)
    mapping(address => bool) public isTrustedForwarder; // contracts that can specify a custom creator

    // Shared schedule subscriptions for resolution end (auto-resolution)
    mapping(uint256 => uint64) internal _sharedEndScheduleSubIdByTs; // timestamp (s) -> shared subscription id
    mapping(uint256 => bool) internal _marketResolutionEmitted; // marketId -> whether MarketResolved was emitted
    mapping(uint256 => bool) private _marketVoided; // marketId -> whether resolver explicitly voided

    /// @notice The ID for the next market to be created.
    uint256 public nextLocalId;

    /// @notice Maps a market ID to its local data and state.
    mapping(uint256 => MarketLocal) public marketData;

    /// @notice Maps a market ID and group ID to a specific condition group.
    mapping(uint256 => mapping(uint256 => ConditionGroup)) public conditionGroups;

    event OCEMReactivityUnsubscribeTopic(
        uint256 indexed marketId, uint256 indexed subscriptionId, uint256 timestampMs, bool success
    );
    event OCEMReactivityUnsubscribeStartSchedule(
        uint256 indexed marketId, uint256 indexed subscriptionId, uint256 timestampMs
    );
    event OCEMReactivityUnsubscribeEndSchedule(
        uint256 indexed marketId, uint256 indexed subscriptionId, uint256 timestampMs
    );
    event OCEMReactivityUnsubscribeSharedEndCleanup(
        uint256 indexed marketId, uint256 indexed subscriptionId, uint256 timestampMs
    );

    event SubscriptionCreated(address eventSource, uint64 subscriptionId);
    event SubscriptionEnded(address eventSource, uint64 subscriptionId);

    /// @notice Emitted when a condition group's criteria are met by an on-chain event.
    /// @param firstSatisfaction True if this is the first time this specific group has been satisfied.
    event ConditionGroupMatched(
        uint256 indexed marketId, uint256 indexed groupId, uint256 newPassCount, bool firstSatisfaction
    );

    /// @notice Emitted when a new condition group is registered for a market.
    event ConditionGroupRegistered(
        uint256 indexed marketId,
        uint256 indexed groupId,
        address contractAddr,
        string eventSignature,
        uint256 condCount,
        string logicalOp,
        OccurrenceType occurrenceType,
        uint256 occurrenceValue
    );

    // Diagnostic: emitted for every evaluation attempt (whether it matched or not)
    event ConditionGroupChecked(
        uint256 indexed marketId, uint256 indexed groupId, bool matched, uint256 passCountBefore, uint256 passCountAfter
    );

    event MarketVoided(uint256 indexed marketId, address indexed resolver);

    event MarketCreationFailed(uint256 venueId, address creator, string reason);
    event MarketResolved(uint256 indexed marketId, uint8 outcome);

    event SettlementFinalizationFailed(uint256 indexed marketId, bytes reason);
    event ProphecyCoreAddressUpdated(address indexed oldAddr, address indexed newAddr);
    event CreateMarket_Attempt(address indexed sender, uint256 value); // For diagnostics

    // --- Event Name Generation Events ---
    event EventNameGenRequested(uint256 indexed eventId, uint256 requestId);
    event NameGenCallbackReceived(uint256 indexed requestId, uint8 status, uint256 receiptId);
    event NameGenUnmappedRequest(uint256 indexed requestId);
    /// @param reason 1 = agent returned non-Success status or empty results,
    ///               2 = decoded string was empty
    event EventNameGenFailed(uint256 indexed eventId, uint256 requestId, uint8 reason, uint8 status);
    event EventNameGenCompleted(uint256 indexed eventId, string generatedName);

    // --- Debugging Events ---
    event OnEventReceived(address source, bytes32 indexed eventTopic);
    event OnEventNoMatchingGroups(bytes32 indexed key);
    event OnEventProcessingGroup(uint256 indexed marketId, uint256 indexed groupId);
    event GroupEvaluationSkipped(uint256 indexed marketId, uint256 indexed groupId, string reason);
    event ConditionEvaluated(uint256 indexed marketId, uint256 indexed groupId, uint256 conditionIndex, bool result);
    event GroupEvaluated(uint256 indexed marketId, uint256 indexed groupId, bool result);

    /// @notice Accept native token transfers (e.g., forwarded subscription funding).
    receive() external payable { }

    // ------------------- Subscription management (inlined from SubscriptionManager) -------------------

    function _createSubscription(
        address eventSource,
        bytes32 eventTopic
    ) internal virtual {
        _activateSubscription(eventSource, eventTopic);
    }

    function _endSubscription(
        address eventSource,
        bytes32 eventTopic
    ) internal virtual {
        _deactivateSubscription(0, eventSource, eventTopic);
    }

    function _activateSubscription(
        address eventSource,
        bytes32 eventTopic
    ) internal {
        if (eventSource == address(0)) revert ZeroEventAddress();
        if (eventTopic == bytes32(0)) revert ZeroEventTopic();

        bytes32 subKey = keccak256(abi.encodePacked(eventSource, eventTopic));
        if (_activeSubscriptionCounts[subKey] == 0 && _subscriptionIds[subKey] == 0) {
            ISomniaReactivityPrecompile.SubscriptionData memory subData = ISomniaReactivityPrecompile.SubscriptionData({
                eventTopics: [eventTopic, bytes32(0), bytes32(0), bytes32(0)],
                origin: address(0),
                caller: address(0),
                emitter: eventSource,
                handlerContractAddress: address(this),
                handlerFunctionSelector: ISomniaEventHandler.onEvent.selector,
                priorityFeePerGas: uint64(10 gwei),
                maxFeePerGas: uint64(20 gwei),
                gasLimit: 100_000_000,
                isGuaranteed: true,
                isCoalesced: false
            });

            uint64 subscriptionId = uint64(_reactivityPrecompile.subscribe(subData));
            _subscriptionIds[subKey] = subscriptionId;
            emit SubscriptionCreated(eventSource, subscriptionId);
        }
        _activeSubscriptionCounts[subKey] += 1;
    }

    function _deactivateSubscription(
        uint256 marketId,
        address eventSource,
        bytes32 eventTopic
    ) internal {
        if (eventSource == address(0)) revert ZeroEventAddress();
        if (eventTopic == bytes32(0)) revert ZeroEventTopic();

        bytes32 subKey = keccak256(abi.encodePacked(eventSource, eventTopic));
        uint256 count = _activeSubscriptionCounts[subKey];
        if (count == 0) {
            return;
        }
        count -= 1;
        _activeSubscriptionCounts[subKey] = count;

        if (count == 0) {
            uint64 subscriptionId = _subscriptionIds[subKey];
            if (subscriptionId != 0) {
                bool success = false;
                // Note: We have to wrap the unsubscribe call like this as it has no return value, which causes an issue when calling the precompile from Solidity.
                (success,) = address(_reactivityPrecompile)
                    .call(abi.encodeWithSelector(_reactivityPrecompile.unsubscribe.selector, subscriptionId));
                emit OCEMReactivityUnsubscribeTopic(marketId, subscriptionId, block.timestamp * 1000, success);
                delete _subscriptionIds[subKey];
                emit SubscriptionEnded(eventSource, subscriptionId);
            }
        }
    }

    function _scheduleResolutionSubscribe(
        uint256 marketId,
        uint256 resolutionStartTs
    ) internal virtual {
        // No need to schedule if start time already passed.
        if (resolutionStartTs == 0 || resolutionStartTs <= block.timestamp) return;

        uint256 scheduleTimestampMs = uint256(resolutionStartTs) * 1000;
        ISomniaReactivityPrecompile.SubscriptionData memory subData = ISomniaReactivityPrecompile.SubscriptionData({
            eventTopics: [
                ISomniaReactivityPrecompile.Schedule.selector, bytes32(scheduleTimestampMs), bytes32(0), bytes32(0)
            ],
            origin: address(0),
            caller: address(0),
            emitter: SomniaExtensions.SOMNIA_REACTIVITY_PRECOMPILE_ADDRESS,
            handlerContractAddress: address(this),
            handlerFunctionSelector: ISomniaEventHandler.onEvent.selector,
            priorityFeePerGas: uint64(10 gwei),
            maxFeePerGas: uint64(20 gwei),
            gasLimit: 100_000_000,
            isGuaranteed: true,
            isCoalesced: false
        });

        uint64 subId = uint64(_reactivityPrecompile.subscribe(subData));
        _resolutionStartScheduleSubIds[marketId] = subId;
        _marketToResolutionStartTimestampSec[marketId] = resolutionStartTs;
        _marketsToSubscribeByTimestampSec[resolutionStartTs].push(marketId);
    }

    function _scheduleResolutionUnsubscribe(
        uint256 marketId,
        uint256 resolutionEndTs
    ) internal virtual {
        // Track which timestamp this market uses for resolution end
        _marketToResolutionEndTimestampSec[marketId] = resolutionEndTs;
        _marketsToUnsubscribeByTimestampSec[resolutionEndTs].push(marketId);

        // Only create a new subscription if one doesn't already exist for this timestamp
        if (_sharedEndScheduleSubIdByTs[resolutionEndTs] == 0) {
            uint256 scheduleTimestampMs = uint256(resolutionEndTs) * 1000;
            ISomniaReactivityPrecompile.SubscriptionData memory subData = ISomniaReactivityPrecompile.SubscriptionData({
                eventTopics: [
                    ISomniaReactivityPrecompile.Schedule.selector, bytes32(scheduleTimestampMs), bytes32(0), bytes32(0)
                ],
                origin: address(0),
                caller: address(0),
                emitter: SomniaExtensions.SOMNIA_REACTIVITY_PRECOMPILE_ADDRESS,
                handlerContractAddress: address(this),
                handlerFunctionSelector: ISomniaEventHandler.onEvent.selector,
                priorityFeePerGas: uint64(10 gwei),
                maxFeePerGas: uint64(20 gwei),
                gasLimit: 100_000_000,
                isGuaranteed: true,
                isCoalesced: false
            });

            uint64 subId = uint64(_reactivityPrecompile.subscribe(subData));
            _sharedEndScheduleSubIdByTs[resolutionEndTs] = subId;
        }
    }

    /// @dev Schedule an overflow callback at the given timestamp. Called when a batch
    ///      exceeds _SCHEDULE_BATCH_SIZE and remaining markets are deferred.
    function _scheduleOverflowCallback(
        uint256 overflowTs
    ) internal virtual {
        uint256 scheduleTimestampMs = overflowTs * 1000;
        ISomniaReactivityPrecompile.SubscriptionData memory subData = ISomniaReactivityPrecompile.SubscriptionData({
            eventTopics: [
                ISomniaReactivityPrecompile.Schedule.selector, bytes32(scheduleTimestampMs), bytes32(0), bytes32(0)
            ],
            origin: address(0),
            caller: address(0),
            emitter: SomniaExtensions.SOMNIA_REACTIVITY_PRECOMPILE_ADDRESS,
            handlerContractAddress: address(this),
            handlerFunctionSelector: ISomniaEventHandler.onEvent.selector,
            priorityFeePerGas: uint64(10 gwei),
            maxFeePerGas: uint64(20 gwei),
            gasLimit: 100_000_000,
            isGuaranteed: true,
            isCoalesced: false
        });

        uint64 subId = uint64(_reactivityPrecompile.subscribe(subData));
        _sharedEndScheduleSubIdByTs[overflowTs] = subId;
    }

    function _cancelResolutionSchedule(
        uint256 marketId
    ) internal {
        // Cancel start schedule if present
        uint64 startSubId = _resolutionStartScheduleSubIds[marketId];
        if (startSubId != 0) {
            emit OCEMReactivityUnsubscribeStartSchedule(marketId, startSubId, block.timestamp * 1000);
            delete _resolutionStartScheduleSubIds[marketId];
        }
        uint256 startTs = _marketToResolutionStartTimestampSec[marketId];
        if (startTs != 0) {
            uint256[] storage startArr = _marketsToSubscribeByTimestampSec[startTs];
            uint256 startArrLen = startArr.length;
            for (uint256 i; i < startArrLen; i++) {
                if (startArr[i] == marketId) {
                    startArr[i] = startArr[startArr.length - 1];
                    startArr.pop();
                    break;
                }
            }
            if (startArr.length == 0) {
                delete _marketsToSubscribeByTimestampSec[startTs];
            }
            delete _marketToResolutionStartTimestampSec[marketId];
        }

        // Cancel end schedule if present (using shared subscription model)
        uint256 endTs = _marketToResolutionEndTimestampSec[marketId];
        if (endTs != 0) {
            uint256[] storage endArr = _marketsToUnsubscribeByTimestampSec[endTs];
            uint256 endArrLen = endArr.length;
            for (uint256 i; i < endArrLen; i++) {
                if (endArr[i] == marketId) {
                    endArr[i] = endArr[endArr.length - 1];
                    endArr.pop();
                    break;
                }
            }
            // Only clean up the shared subscription if no more markets use this timestamp
            if (endArr.length == 0) {
                delete _marketsToUnsubscribeByTimestampSec[endTs];
                uint64 sharedSubId = _sharedEndScheduleSubIdByTs[endTs];
                if (sharedSubId != 0) {
                    emit OCEMReactivityUnsubscribeEndSchedule(marketId, sharedSubId, block.timestamp * 1000);
                    delete _sharedEndScheduleSubIdByTs[endTs];
                }
            }
            delete _marketToResolutionEndTimestampSec[marketId];
        }
    }

    function _handleResolutionSchedule(
        bytes32[] calldata,
        bytes calldata
    ) internal {
        uint256 timestamp = block.timestamp;

        // --- SUBSCRIBE PATH ---
        // Check for overflow redirect from a prior batch
        uint256 subRedirectSource = _overflowSubscribeSourceTs[timestamp];
        if (subRedirectSource != 0) delete _overflowSubscribeSourceTs[timestamp];

        bool subRemainOrganic = _processBatchSubscribe(timestamp);
        bool subRemainRedirect = subRedirectSource != 0 ? _processBatchSubscribe(subRedirectSource) : false;

        // --- UNSUBSCRIBE PATH ---
        uint256 unsubRedirectSource = _overflowUnsubscribeSourceTs[timestamp];
        if (unsubRedirectSource != 0) delete _overflowUnsubscribeSourceTs[timestamp];

        bool unsubRemainOrganic = _processBatchUnsubscribe(timestamp);
        bool unsubRemainRedirect = unsubRedirectSource != 0 ? _processBatchUnsubscribe(unsubRedirectSource) : false;

        // Clean up shared schedule subscription (callback already fired)
        uint64 sharedSubId = _sharedEndScheduleSubIdByTs[timestamp];
        if (sharedSubId != 0) {
            emit OCEMReactivityUnsubscribeSharedEndCleanup(0, sharedSubId, block.timestamp * 1000);
            delete _sharedEndScheduleSubIdByTs[timestamp];
        }

        // --- SCHEDULE OVERFLOW ---
        bool subOverflow = subRemainOrganic || subRemainRedirect;
        bool unsubOverflow = unsubRemainOrganic || unsubRemainRedirect;
        if (!subOverflow && !unsubOverflow) return;

        uint256 overflowTs = timestamp + _OVERFLOW_DELAY_SEC;

        // Subscribe: resolve which source array to redirect to
        if (subRemainOrganic && subRemainRedirect) {
            // Rare: both organic and redirected remain — merge organic into redirect source
            _mergeArrayInto(
                _marketsToSubscribeByTimestampSec[timestamp], _marketsToSubscribeByTimestampSec[subRedirectSource]
            );
            delete _marketsToSubscribeByTimestampSec[timestamp];
            _overflowSubscribeSourceTs[overflowTs] = subRedirectSource;
        } else if (subRemainOrganic) {
            _overflowSubscribeSourceTs[overflowTs] = timestamp;
        } else if (subRemainRedirect) {
            _overflowSubscribeSourceTs[overflowTs] = subRedirectSource;
        }

        // Unsubscribe: resolve which source array to redirect to
        if (unsubRemainOrganic && unsubRemainRedirect) {
            _mergeArrayInto(
                _marketsToUnsubscribeByTimestampSec[timestamp], _marketsToUnsubscribeByTimestampSec[unsubRedirectSource]
            );
            delete _marketsToUnsubscribeByTimestampSec[timestamp];
            _overflowUnsubscribeSourceTs[overflowTs] = unsubRedirectSource;
        } else if (unsubRemainOrganic) {
            _overflowUnsubscribeSourceTs[overflowTs] = timestamp;
        } else if (unsubRemainRedirect) {
            _overflowUnsubscribeSourceTs[overflowTs] = unsubRedirectSource;
        }

        // Schedule overflow callback if not already scheduled for that timestamp
        if (_sharedEndScheduleSubIdByTs[overflowTs] == 0) {
            _scheduleOverflowCallback(overflowTs);
        }
    }

    /// @dev Pop up to _SCHEDULE_BATCH_SIZE markets from the end of the subscribe
    ///      array at `sourceTs` and activate their event subscriptions.
    /// @return hasRemaining True if the array still has entries after processing.
    function _processBatchSubscribe(
        uint256 sourceTs
    ) internal returns (bool hasRemaining) {
        uint256[] storage arr = _marketsToSubscribeByTimestampSec[sourceTs];
        uint256 len = arr.length;
        if (len == 0) return false;

        uint256 batchSize = len > _SCHEDULE_BATCH_SIZE ? _SCHEDULE_BATCH_SIZE : len;

        for (uint256 i; i < batchSize; i++) {
            uint256 marketId = arr[arr.length - 1];
            arr.pop();

            MarketLocal storage ml = marketData[marketId];
            if (ml.subscriptionsActive) continue;
            uint256 totalCG = ml.totalConditionGroups;
            for (uint256 g; g < totalCG; g++) {
                ConditionGroup storage cg = conditionGroups[marketId][g];
                bytes32 eventTopic = keccak256(bytes(cg.eventSignature));
                bytes32 key = keccak256(abi.encodePacked(cg.contractAddr, eventTopic));
                _addEventSubscriber(key, (marketId << 128) | g);
                _createSubscription(cg.contractAddr, eventTopic);
            }
            ml.subscriptionsActive = true;
        }

        hasRemaining = arr.length > 0;
        if (!hasRemaining) delete _marketsToSubscribeByTimestampSec[sourceTs];
    }

    /// @dev Pop up to _SCHEDULE_BATCH_SIZE markets from the end of the unsubscribe
    ///      array at `sourceTs`, emit resolution events, finalize settlement, and clean up.
    /// @return hasRemaining True if the array still has entries after processing.
    function _processBatchUnsubscribe(
        uint256 sourceTs
    ) internal returns (bool hasRemaining) {
        uint256[] storage arr = _marketsToUnsubscribeByTimestampSec[sourceTs];
        uint256 len = arr.length;
        if (len == 0) return false;

        uint256 batchSize = len > _SCHEDULE_BATCH_SIZE ? _SCHEDULE_BATCH_SIZE : len;

        for (uint256 i; i < batchSize; i++) {
            uint256 marketId = arr[arr.length - 1];
            arr.pop();

            // Emit MarketResolved if not already emitted for this market
            if (!_marketResolutionEmitted[marketId]) {
                uint8 outcome = _finalOutcomeTriState(marketId);
                _marketResolutionEmitted[marketId] = true;
                emit MarketResolved(marketId, outcome);
            }

            // Best-effort finalize settlement so data is available immediately
            try prophecyCore.settlementContract().finalizeMarket(marketId) { }
            catch (bytes memory reason) {
                emit SettlementFinalizationFailed(marketId, reason);
            }

            _endMarketSubscriptions(marketId);
        }

        hasRemaining = arr.length > 0;
        if (!hasRemaining) delete _marketsToUnsubscribeByTimestampSec[sourceTs];
    }

    /// @dev Append all entries from `src` to `dst`. Does not clear `src`.
    function _mergeArrayInto(
        uint256[] storage src,
        uint256[] storage dst
    ) internal {
        uint256 len = src.length;
        for (uint256 i; i < len; i++) {
            dst.push(src[i]);
        }
    }

    function _endMarketSubscriptions(
        uint256 marketId
    ) internal {
        _endEventSubscriptionsOnly(marketId);
        _removeAllEventSubscriberEntries(marketId);
        _cancelResolutionSchedule(marketId);
    }

    function _endEventSubscriptionsOnly(
        uint256 marketId
    ) internal {
        MarketLocal storage ml = marketData[marketId];
        if (!ml.subscriptionsActive) {
            return;
        }
        uint256 totalGroups = ml.totalConditionGroups;
        for (uint256 i = 0; i < totalGroups; i++) {
            ConditionGroup storage cg = conditionGroups[marketId][i];
            bytes32 eventTopic = keccak256(bytes(cg.eventSignature));
            address eventSource = cg.contractAddr;
            _deactivateSubscription(marketId, eventSource, eventTopic);
        }
        ml.subscriptionsActive = false;
    }

    /// @dev Remove all event subscriber array entries for a market. Safe to call
    ///      regardless of subscriptionsActive — idempotent via index check.
    ///      Must NOT be called from within the _onEvent iteration loop.
    function _removeAllEventSubscriberEntries(
        uint256 marketId
    ) internal {
        MarketLocal storage ml = marketData[marketId];
        uint256 totalGroups = ml.totalConditionGroups;
        for (uint256 i = 0; i < totalGroups; i++) {
            ConditionGroup storage cg = conditionGroups[marketId][i];
            bytes32 eventTopic = keccak256(bytes(cg.eventSignature));
            bytes32 key = keccak256(abi.encodePacked(cg.contractAddr, eventTopic));
            uint256 packed = (marketId << 128) | i;
            _removeEventSubscriber(key, packed);
        }
    }

    /// @dev Add a market/group entry to the event subscriber array with index tracking.
    function _addEventSubscriber(
        bytes32 key,
        uint256 packed
    ) internal {
        _eventSubscribers[key].push(packed);
        _eventSubscriberIndex[key][packed] = _eventSubscribers[key].length; // 1-indexed
    }

    /// @dev Remove a market/group entry from the event subscriber array via swap-and-pop.
    function _removeEventSubscriber(
        bytes32 key,
        uint256 packed
    ) internal {
        uint256 idx1 = _eventSubscriberIndex[key][packed]; // 1-indexed
        if (idx1 == 0) return; // not in array

        uint256[] storage list = _eventSubscribers[key];
        uint256 lastIdx = list.length - 1;
        uint256 idx = idx1 - 1; // 0-indexed

        if (idx != lastIdx) {
            uint256 lastPacked = list[lastIdx];
            list[idx] = lastPacked;
            _eventSubscriberIndex[key][lastPacked] = idx1;
        }

        list.pop();
        delete _eventSubscriberIndex[key][packed];
    }

    /**
     * @notice Updates the address of the ProphecyCore contract.
     * @dev Can only be called by the owner of this contract. Emits a `ProphecyCoreAddressUpdated` event.
     * @param newProphecyCore The address of the new ProphecyCore contract.
     */
    function setProphecyCore(
        IProphecyCore newProphecyCore
    ) external onlyOwner {
        if (address(newProphecyCore) == address(0)) revert ZeroAddr();
        address old = address(prophecyCore);
        prophecyCore = newProphecyCore;
        emit ProphecyCoreAddressUpdated(old, address(newProphecyCore));
    }

    /**
     * @notice Sets whether an address is a trusted forwarder that can specify custom creators.
     * @dev Trusted forwarders (e.g., AIResolutionMarket) can pass through the original caller's address.
     * @param forwarder The address to set trust status for.
     * @param allowed Whether the address should be trusted.
     */
    function allowResolver(
        address forwarder,
        bool allowed
    ) external onlyOwner {
        isTrustedForwarder[forwarder] = allowed;
    }

    /// @notice Update the Somnia agent platform address for name generation.
    function setNameAgentPlatform(
        address platform
    ) external onlyOwner {
        if (platform == address(0)) revert ZeroAddr();
        nameAgentPlatform = IHttpSingletonSomniaAgents(platform);
    }

    /// @notice Set the system prompt used for AI name generation.
    function setNameGenPrompt(
        string calldata prompt
    ) external onlyOwner {
        nameGenPrompt = prompt;
    }

    /**
     * @notice Allows a market's registered resolver to explicitly void the market.
     * @dev Used by resolver wrappers (AI, Creator) that detect absence themselves.
     *      The voided state overrides the condition-based outcome in outcomeFor().
     * @param marketId The ID of the market to void.
     */
    function voidMarket(
        uint256 marketId
    ) external nonReentrant {
        (IProphecyCore.MarketCore memory core,) = prophecyCore.getMarketCore(marketId);
        if (msg.sender != core.resolver && !isTrustedForwarder[msg.sender]) {
            revert NotMarketResolver();
        }
        if (block.timestamp < core.resolutionStartTs) revert ResolutionWindowNotOpen();
        if (core.resolved || marketData[marketId].conditionsSatisfied) revert MarketAlreadyResolved();
        _marketVoided[marketId] = true;
        emit MarketVoided(marketId, msg.sender);
    }

    /**
     * @dev Determines the effective creator address for market registration.
     * If providedCreator is address(0), uses msg.sender.
     * If providedCreator is specified and caller is a trusted forwarder, uses providedCreator.
     * Otherwise, uses msg.sender (prevents untrusted contracts from spoofing creators).
     * @param providedCreator The creator address provided in params (address(0) for direct calls).
     * @return The effective creator address to use.
     */
    function _getCreator(
        address providedCreator
    ) internal view returns (address) {
        if (providedCreator == address(0)) {
            return msg.sender;
        }
        if (isTrustedForwarder[msg.sender]) {
            return providedCreator;
        }
        return msg.sender;
    }

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    function initialize(
        IProphecyCore prophecyCoreAddr,
        address owner
    ) public initializer {
        __UUPSUpgradeable_init();
        __ReentrancyGuard_init();
        prophecyCore = prophecyCoreAddr;
        __Ownable_init(owner);
        _reactivityPrecompile = ISomniaReactivityPrecompile(SomniaExtensions.SOMNIA_REACTIVITY_PRECOMPILE_ADDRESS);
        nextLocalId = 1;
    }

    /// @notice Expose the reactivity precompile address.
    function getReactivityPrecompile() external view returns (ISomniaReactivityPrecompile) {
        return _reactivityPrecompile;
    }

    function _authorizeUpgrade(
        address
    ) internal override onlyOwner { }

    /**
     * @notice Creates a new prediction market with extended options.
     * @dev This is an extended version of `createMarket` that allows specifying the logical operator for combining condition groups.
     * @param p The market creation parameters struct containing all configuration.
     * @return marketId The unique identifier for the newly created market.
     */
    function createMarketEx(
        CreateMarketParams calldata p
    ) public payable nonReentrant returns (uint256 marketId) {
        marketId = _createMarketInternal(
            p.name,
            p.venueId,
            p.venueSignature,
            p.stakeToken,
            p.tradingStartTs,
            p.tradingEndTs,
            p.resolutionStartTs,
            p.resolutionEndTs,
            p.inputs,
            p.groupsLogicalOp,
            p.initialLiquidityBase,
            p.noMatchOutcome,
            p.resolverType,
            p.creator,
            p.resolver,
            p.deadline,
            0, // eventId = 0 (auto-create single-market event)
            p.eventContext,
            p.skipNameGen
        );
    }

    /**
     * @notice Creates a new prediction market with extended options including event grouping.
     * @dev V2 adds eventId for grouping multiple markets under a single event.
     * @param p The market creation parameters struct containing all configuration.
     * @return marketId The unique identifier for the newly created market.
     */
    function createMarketExV2(
        CreateMarketParamsV2 calldata p
    ) public payable nonReentrant returns (uint256 marketId) {
        marketId = _createMarketInternal(
            p.name,
            p.venueId,
            p.venueSignature,
            p.stakeToken,
            p.tradingStartTs,
            p.tradingEndTs,
            p.resolutionStartTs,
            p.resolutionEndTs,
            p.inputs,
            p.groupsLogicalOp,
            p.initialLiquidityBase,
            p.noMatchOutcome,
            p.resolverType,
            p.creator,
            p.resolver,
            p.deadline,
            p.eventId,
            p.eventContext,
            p.skipNameGen
        );
    }

    /// @dev Shared implementation for createMarketEx and createMarketExV2.
    function _createMarketInternal(
        string calldata name,
        uint256 venueId,
        bytes calldata venueSignature,
        address stakeToken,
        uint256 tradingStartTs,
        uint256 tradingEndTs,
        uint256 resolutionStartTs,
        uint256 resolutionEndTs,
        ConditionInput[] calldata inputs,
        LogicalOperator groupsLogicalOp,
        uint256 initialLiquidityBase,
        uint8 noMatchOutcome,
        uint8 resolverType,
        address creator,
        address resolver,
        uint256 deadline,
        uint256 eventId,
        bytes calldata eventContext,
        bool skipNameGen
    ) internal returns (uint256 marketId) {
        if (inputs.length == 0) revert NoGroups();
        address prophecyCoreAddr = address(prophecyCore);
        (, uint256 initialLiquidity) = LiquidityLib.computeInitialLiquidity(prophecyCoreAddr, initialLiquidityBase);

        uint256 prophecyCoreValue = stakeToken == address(0) ? initialLiquidity : 0;

        address effectiveCreator = _getCreator(creator);

        // Value and venue checks: skip for trusted forwarders (they validate upstream)
        if (!isTrustedForwarder[msg.sender]) {
            uint256 nameGenDep = skipNameGen ? 0 : getNameGenCost();
            uint256 fundsLeaving = prophecyCoreValue + nameGenDep;
            uint256 preCallBalance = address(this).balance - msg.value;
            uint256 effective = preCallBalance > fundsLeaving ? preCallBalance - fundsLeaving : 0;
            uint256 topUp = effective >= MIN_SUBSCRIPTION_BALANCE ? 0 : MIN_SUBSCRIPTION_BALANCE - effective;
            uint256 requiredValue = fundsLeaving + topUp;
            if (msg.value < requiredValue) revert IncorrectMsgValue();

            VenuePermitLib.verifyCreateMarketPermit(
                IProphecyCore(prophecyCoreAddr).venueGating(),
                name,
                venueId,
                venueSignature,
                effectiveCreator,
                stakeToken,
                tradingStartTs,
                tradingEndTs,
                resolutionStartTs,
                resolutionEndTs,
                initialLiquidityBase,
                noMatchOutcome,
                resolverType,
                deadline
            );
        }

        IProphecyCore.MarketRegistrationParams memory regParams = IProphecyCore.MarketRegistrationParams({
            name: name,
            venueId: venueId,
            venueSignature: "",
            creator: effectiveCreator,
            stakeToken: stakeToken,
            tradingStartTs: tradingStartTs,
            tradingEndTs: tradingEndTs,
            resolutionStartTs: resolutionStartTs,
            resolutionEndTs: resolutionEndTs,
            initialLiquidityBase: initialLiquidityBase,
            noMatchOutcome: noMatchOutcome,
            resolverType: resolverType,
            deadline: 0
        });

        address effectiveResolver = resolver == address(0) ? address(this) : resolver;
        if (resolver != address(0) && !isTrustedForwarder[msg.sender]) {
            revert UntrustedResolverOverride();
        }

        marketId = prophecyCore.registerMarket{ value: prophecyCoreValue }(
            regParams, address(this), effectiveResolver, eventId, eventContext
        );

        MarketDataLib.initMarketLocal(marketData[marketId], resolutionStartTs, resolutionEndTs, groupsLogicalOp);

        bool activateNow = resolutionStartTs == 0 || resolutionStartTs <= block.timestamp;

        for (uint256 i; i < inputs.length; i++) {
            _createGroup(marketId, inputs[i], activateNow);
        }

        if (activateNow) {
            marketData[marketId].subscriptionsActive = true;
        } else {
            _scheduleResolutionSubscribe(marketId, resolutionStartTs);
        }

        _scheduleResolutionUnsubscribe(marketId, resolutionEndTs);

        if (!skipNameGen) {
            uint256 mEventId = IProphecyCoreEventLookup(address(prophecyCore)).marketEventId(marketId);
            _requestEventNameGeneration(mEventId, name, eventContext);
        }
    }

    /**
     * @dev Internal function to initialize a condition group for a market.
     * It parses the input conditions, creates subscriptions, and stores the group.
     * @param marketId The ID of the market to associate the group with.
     * @param input The user-provided definition of the condition group.
     */
    function _createGroup(
        uint256 marketId,
        ConditionInput calldata input,
        bool activateNow
    ) internal {
        MarketLocal storage ml = marketData[marketId];
        uint256 groupId = ml.totalConditionGroups++;
        ConditionGroup storage cg = conditionGroups[marketId][groupId];
        ConditionBuilderLib.populateGroup(cg, input);

        if (activateNow) {
            bytes32 eventTopic = keccak256(bytes(input.eventSignature));
            bytes32 key = keccak256(abi.encodePacked(input.contractAddr, eventTopic));
            _addEventSubscriber(key, (marketId << 128) | groupId);
            _createSubscription(input.contractAddr, eventTopic);
        }
        emit ConditionGroupRegistered(
            marketId,
            groupId,
            input.contractAddr,
            input.eventSignature,
            input.conditions.length,
            cg.logicalOp == LogicalOperator.AND ? "AND" : "OR",
            input.occurrenceType,
            input.occurrenceValue
        );
    }

    /**
     * @dev Checks a condition group's status and, if valid, proceeds to evaluate it against the raw event data.
     * If the group's conditions are met, it updates the market's progress. If the market's
     * outcome becomes certain, it calls `_checkMarketStatus` to potentially stop event processing.
     * @param marketId The ID of the market being evaluated.
     * @param groupId The ID of the condition group being evaluated.
     * @param eventTopics An array of event topics (including indexed parameters).
     * @param data The ABI-encoded data payload of the event (non-indexed parameters).
     */
    function _evaluateGroupForEvent(
        uint256 marketId,
        uint256 groupId,
        bytes32[] calldata eventTopics,
        bytes calldata data
    ) internal {
        (IProphecyCore.MarketCore memory core,) = prophecyCore.getMarketCore(marketId);

        // Enforce the resolution window; don't evaluate events outside of it.
        if (block.timestamp < core.tradingEndTs) {
            emit GroupEvaluationSkipped(marketId, groupId, "BeforeBettingEnd");
            return;
        }

        if (block.timestamp < core.resolutionStartTs) {
            emit GroupEvaluationSkipped(marketId, groupId, "BeforeResolutionStart");
            return;
        }
        ConditionGroup storage cg = conditionGroups[marketId][groupId];

        // Increment seenCount only for events that pass the relevance filter.
        // If relevanceMask is 0, all events count (backwards compatible).
        if (ConditionEval.evalRelevance(cg, eventTopics, data)) {
            cg.seenCount++;
        }

        if (cg.failed) {
            emit GroupEvaluationSkipped(marketId, groupId, "GroupFailed");
            return;
        }

        if (
            cg.satisfiedEarly
                && (cg.occurrenceType == OccurrenceType.AT_LEAST_ONCE || cg.occurrenceType == OccurrenceType.AT_LEAST)
        ) {
            emit GroupEvaluationSkipped(marketId, groupId, "GroupSatisfiedPermanently");
            return;
        }

        uint256 before = cg.passCount;
        bool matched = ConditionEval.evalGroup(cg, eventTopics, data);
        emit ConditionGroupChecked(marketId, groupId, matched, before, matched ? before + 1 : before);

        if (matched) {
            cg.passCount++;
            uint256 newPassCount = cg.passCount;

            if (cg.occurrenceType == OccurrenceType.NEVER) {
                cg.failed = true; // Any match is a failure
            } else if (cg.occurrenceType == OccurrenceType.AT_LEAST_ONCE) {
                if (!cg.satisfiedEarly) {
                    cg.satisfiedEarly = true; // Met condition
                }
            } else if (cg.occurrenceType == OccurrenceType.EXACTLY) {
                if (newPassCount == cg.occurrenceValue) {
                    cg.satisfiedEarly = true; // Exactly met, could still fail if another event comes
                } else if (newPassCount > cg.occurrenceValue) {
                    cg.failed = true; // Overshot
                }
            } else if (cg.occurrenceType == OccurrenceType.AT_LEAST) {
                if (newPassCount >= cg.occurrenceValue && !cg.satisfiedEarly) {
                    cg.satisfiedEarly = true; // Met condition
                }
            } else if (cg.occurrenceType == OccurrenceType.AT_MOST) {
                if (newPassCount > cg.occurrenceValue) {
                    cg.failed = true; // Overshot
                }
            }
        }

        // If maxRelevantEvents is set and we've seen enough events without
        // satisfying the condition, the group can never be satisfied — fail it.
        // Only applies to AT_LEAST_ONCE and AT_LEAST: these are the only types
        // where early failure is safe. AT_MOST, NEVER, and EXACTLY can only be
        // confirmed at window end (another event could still change the outcome).
        if (
            cg.maxRelevantEvents > 0 && cg.seenCount >= cg.maxRelevantEvents && !cg.satisfiedEarly
                && (cg.occurrenceType == OccurrenceType.AT_LEAST_ONCE || cg.occurrenceType == OccurrenceType.AT_LEAST)
        ) {
            cg.failed = true;
        }

        _checkMarketStatus(marketId);
    }

    /**
     * @dev Checks if a market's final outcome has become irrevocably certain.
     * If so, marks the market's conditions as satisfied, stops event processing,
     * emits MarketResolved, and triggers settlement finalization immediately.
     * The end schedule is kept active for cleanup of remaining subscriptions.
     * @param marketId The ID of the market to check.
     */
    function _checkMarketStatus(
        uint256 marketId
    ) internal {
        if (marketData[marketId].conditionsSatisfied) {
            return;
        }

        MarketLocal storage ml = marketData[marketId];

        if (OutcomeEvalLib.shouldStopProcessing(ml, conditionGroups[marketId])) {
            ml.conditionsSatisfied = true;
            _endEventSubscriptionsOnly(marketId);

            // Early resolution: emit and finalize immediately
            if (!_marketResolutionEmitted[marketId]) {
                uint8 outcome = _finalOutcomeTriState(marketId);
                _marketResolutionEmitted[marketId] = true;
                emit MarketResolved(marketId, outcome);
            }
            try prophecyCore.settlementContract().finalizeMarket(marketId) { }
            catch (bytes memory reason) {
                emit SettlementFinalizationFailed(marketId, reason);
            }
        }
    }

    /**
     * @dev The internal callback function that is triggered by the Somnia Reactivity Precompile.
     * @dev This function is the main entry point for incoming event data. It identifies the event signature from `eventTopics[0]`,
     * looks up all subscribed condition groups, and loops through them, triggering an immediate evaluation for each.
     * It skips evaluation for markets that are already resolved or satisfied.
     * @param emitter The address of the contract that emitted the event.
     * @param eventTopics An array of event topics; `eventTopics[0]` is the keccak256 hash of the event signature, subsequent entries are indexed parameters.
     * @param data The ABI-encoded data payload of the event (non-indexed parameters).
     */
    function _onEvent(
        address emitter,
        bytes32[] calldata eventTopics,
        bytes calldata data
    ) internal override {
        if (eventTopics.length == 0) {
            return; // Or handle error appropriately
        }
        bytes32 eventTopic = eventTopics[0];

        // Handle scheduled resolution-end callbacks first.
        if (
            emitter == SomniaExtensions.SOMNIA_REACTIVITY_PRECOMPILE_ADDRESS
                && eventTopic == ISomniaReactivityPrecompile.Schedule.selector
        ) {
            _handleResolutionSchedule(eventTopics, data);
            return;
        }

        emit OnEventReceived(emitter, eventTopic);

        bytes32 key = keccak256(abi.encodePacked(emitter, eventTopic));
        uint256[] storage list = _eventSubscribers[key];
        if (list.length == 0) {
            emit OnEventNoMatchingGroups(key);
            return;
        }

        // The old two-pass decoding logic is removed. We will now process each group directly.
        uint256 listLen = list.length;
        for (uint256 i = 0; i < listLen; i++) {
            uint256 packed = list[i];
            uint256 marketId = packed >> 128;

            MarketLocal storage ml = marketData[marketId];

            // Skip markets that no longer need event processing. If subscriptions
            // are still active (ref count not yet decremented), clean them up so
            // the shared subscription can be released when no markets remain.
            if (ml.conditionsSatisfied || (ml.resolutionEndTs != 0 && block.timestamp >= ml.resolutionEndTs)) {
                if (ml.subscriptionsActive) {
                    _endEventSubscriptionsOnly(marketId);
                }
                continue;
            }

            uint256 groupId = packed & type(uint128).max;

            emit OnEventProcessingGroup(marketId, groupId);

            // Immediately evaluate the group with the full event data.
            _evaluateGroupForEvent(marketId, groupId, eventTopics, data);
        }
    }

    // ---- Decoding Helpers ----

    // Decoding helpers are moved to ConditionEval library.

    // ---- Scheduling helpers ----

    // Subscription scheduling and lifecycle moved to SubscriptionManager.

    /**
     * @notice Implements the lazy resolution interface for ProphecyCore.
     * @dev This function is called by the ProphecyCore contract to pull the market outcome after the resolution window.
     * @param marketId The ID of the market to resolve.
     * @return outcome The uint8 outcome of the market (0=NO, 1=YES).
     * @return isResolved True if the outcome is definitive, false otherwise (e.g., if called too early).
     */
    function outcomeFor(
        uint256 marketId
    ) external view returns (uint8 outcome, bool isResolved) {
        MarketLocal storage ml = marketData[marketId];
        // Early resolution: conditions irrevocably determined during resolution window
        if (ml.conditionsSatisfied) {
            outcome = _finalOutcomeTriState(marketId);
            return (outcome, true);
        }
        if (block.timestamp < ml.resolutionEndTs) return (0, false);
        // Past resolution window: compute lazily with tri-state (YES/NO/VOIDED)
        outcome = _finalOutcomeTriState(marketId);
        return (outcome, true);
    }

    /**
     * @dev Calculates the final outcome of a market by logically combining the status of all its condition groups.
     * @param marketId The ID of the market.
     * @return The final boolean outcome.
     */
    function _finalOutcome(
        uint256 marketId
    ) internal view returns (bool) {
        return OutcomeEvalLib.finalOutcome(marketData[marketId], conditionGroups[marketId]);
    }

    /**
     * @dev Tri-state outcome: returns 0 (NO), 1 (YES), or 2 (VOIDED).
     * @param marketId The ID of the market.
     * @return The uint8 outcome.
     */
    function _finalOutcomeTriState(
        uint256 marketId
    ) internal view returns (uint8) {
        return
            OutcomeEvalLib.finalOutcomeTriState(
                marketData[marketId], conditionGroups[marketId], _marketVoided[marketId]
            );
    }

    /**
     * @dev Determines if a single condition group is considered satisfied at the end of the resolution period.
     * @param marketId The ID of the market.
     * @param groupId The ID of the group within the market.
     * @return True if the group's final state meets its occurrence requirements.
     */
    function _isGroupSatisfied(
        uint256 marketId,
        uint256 groupId
    ) internal view returns (bool) {
        return OutcomeEvalLib.isGroupSatisfied(conditionGroups[marketId][groupId]);
    }

    // ===== Debug / Diagnostic Views =====

    /**
     * @notice A debug view to inspect the state of a specific condition group.
     * @dev Shows details for the first condition (`condition[0]`) as a representative sample.
     * @param marketId The ID of the market.
     * @param groupId The ID of the condition group.
     */
    function debugGroup(
        uint256 marketId,
        uint256 groupId
    )
        external
        view
        returns (
            address contractAddr,
            string memory eventSignature,
            uint256 condLen,
            uint256 paramIndex,
            ParamType paramType,
            bytes32 value,
            uint256 passCount,
            bool satisfiedEarly,
            bool failed,
            OccurrenceType occurrenceType,
            uint256 occurrenceValue,
            uint8 absenceOutcome,
            uint256 seenCount
        )
    {
        ConditionGroup storage cg = conditionGroups[marketId][groupId];
        if (cg.conditions.length == 0) {
            return (
                cg.contractAddr,
                cg.eventSignature,
                0,
                0,
                ParamType.UINT, // Default value for empty conditions
                bytes32(0),
                cg.passCount,
                cg.satisfiedEarly,
                cg.failed,
                cg.occurrenceType,
                cg.occurrenceValue,
                cg.absenceOutcome,
                cg.seenCount
            );
        }
        InternalCondition storage ic = cg.conditions[0];
        return (
            cg.contractAddr,
            cg.eventSignature,
            cg.conditions.length,
            ic.paramIndex,
            ic.paramType,
            ic.value,
            cg.passCount,
            cg.satisfiedEarly,
            cg.failed,
            cg.occurrenceType,
            cg.occurrenceValue,
            cg.absenceOutcome,
            cg.seenCount
        );
    }

    /**
     * @notice A debug view to get the hash of a specific condition's value.
     * @param marketId The ID of the market.
     * @param groupId The ID of the group.
     * @param conditionIndex The index of the condition within the group.
     * @return The keccak256 hash of the condition's `value`.
     */
    function conditionHash(
        uint256 marketId,
        uint256 groupId,
        uint256 conditionIndex
    ) external view returns (bytes32) {
        ConditionGroup storage cg = conditionGroups[marketId][groupId];
        if (conditionIndex >= cg.conditions.length) return bytes32(0);
        return keccak256(abi.encodePacked(cg.conditions[conditionIndex].value));
    }

    // ===== Getters =====

    /**
     * @notice Returns all conditions within a specific condition group.
     * @param marketId The ID of the market.
     * @param groupId The ID of the condition group.
     * @return An array of InternalCondition structs.
     */
    function getConditions(
        uint256 marketId,
        uint256 groupId
    ) external view returns (InternalCondition[] memory) {
        return conditionGroups[marketId][groupId].conditions;
    }

    /**
     * @notice Returns the full state of a specific condition group.
     * @param marketId The ID of the market.
     * @param groupId The ID of the condition group.
     */
    function getConditionGroup(
        uint256 marketId,
        uint256 groupId
    )
        external
        view
        returns (
            address contractAddr,
            string memory eventSignature,
            InternalCondition[] memory conditions,
            LogicalOperator logicalOp,
            OccurrenceType occurrenceType,
            uint256 occurrenceValue,
            uint256 passCount,
            bool satisfiedEarly,
            bool failed,
            uint8 absenceOutcome,
            uint256 seenCount
        )
    {
        ConditionGroup storage cg = conditionGroups[marketId][groupId];
        return (
            cg.contractAddr,
            cg.eventSignature,
            cg.conditions,
            cg.logicalOp,
            cg.occurrenceType,
            cg.occurrenceValue,
            cg.passCount,
            cg.satisfiedEarly,
            cg.failed,
            cg.absenceOutcome,
            cg.seenCount
        );
    }

    /**
     * @notice Returns all condition groups for a market.
     * @param marketId The ID of the market.
     * @return groups An array of ConditionGroup structs for every group in the market.
     */
    function getMarketConditions(
        uint256 marketId
    ) external view returns (ConditionGroup[] memory groups) {
        uint256 total = marketData[marketId].totalConditionGroups;
        groups = new ConditionGroup[](total);
        for (uint256 i; i < total; i++) {
            ConditionGroup storage cg = conditionGroups[marketId][i];
            groups[i].contractAddr = cg.contractAddr;
            groups[i].eventSignature = cg.eventSignature;
            groups[i].logicalOp = cg.logicalOp;
            groups[i].occurrenceType = cg.occurrenceType;
            groups[i].occurrenceValue = cg.occurrenceValue;
            groups[i].passCount = cg.passCount;
            groups[i].satisfiedEarly = cg.satisfiedEarly;
            groups[i].failed = cg.failed;
            groups[i].maxParamIndexInGroup = cg.maxParamIndexInGroup;
            groups[i].absenceOutcome = cg.absenceOutcome;
            groups[i].seenCount = cg.seenCount;
            // Copy conditions array
            uint256 condLen = cg.conditions.length;
            InternalCondition[] memory conds = new InternalCondition[](condLen);
            for (uint256 j; j < condLen; j++) {
                conds[j] = cg.conditions[j];
            }
            groups[i].conditions = conds;
        }
    }

    /**
     * @notice Returns the local market state for a given market.
     * @param marketId The ID of the market.
     */
    function getMarketLocal(
        uint256 marketId
    ) external view returns (MarketLocal memory) {
        return marketData[marketId];
    }

    /**
     * @notice Returns whether a market has been explicitly voided by its resolver.
     * @param marketId The ID of the market.
     */
    function isMarketVoided(
        uint256 marketId
    ) external view returns (bool) {
        return _marketVoided[marketId];
    }

    // ===== Cost Estimation =====

    /// @notice Returns the total msg.value required to create a single market.
    ///         Includes a 5% buffer to absorb balance changes between the view
    ///         call and transaction execution (reactivity callbacks can drain
    ///         the balance between blocks). Excess stays in OCEM.
    /// @param initialLiquidityBase The base liquidity amount for the market.
    /// @param stakeToken The stake token address (address(0) for native STT).
    /// @param skipNameGen Whether name generation is skipped.
    function getCreateMarketCost(
        uint256 initialLiquidityBase,
        address stakeToken,
        bool skipNameGen
    ) public view returns (uint256) {
        (, uint256 initialLiquidity) = LiquidityLib.computeInitialLiquidity(address(prophecyCore), initialLiquidityBase);
        uint256 liquidityValue = stakeToken == address(0) ? initialLiquidity : 0;
        uint256 nameGenDep = skipNameGen ? 0 : getNameGenCost();
        uint256 fundsLeaving = liquidityValue + nameGenDep;
        uint256 bal = address(this).balance;
        uint256 effective = bal > fundsLeaving ? bal - fundsLeaving : 0;
        uint256 topUp = effective >= MIN_SUBSCRIPTION_BALANCE ? 0 : MIN_SUBSCRIPTION_BALANCE - effective;
        uint256 total = fundsLeaving + topUp;
        return total + (total * _COST_BUFFER_BPS) / 10_000;
    }

    // ===== Name Generation =====

    /// @notice Returns the agent deposit required for name generation, or 0 if not configured.
    /// @dev Sum of the contract-side operations reserve (via
    ///      `getAdvancedRequestDeposit`, covers callback/finalisation gas) and
    ///      the per-agent execution reward. Matches the runner's admission rule
    ///      `perAgentBudget >= scheduledExecutionCost` (see AGT-282).
    function getNameGenCost() public view returns (uint256) {
        if (address(nameAgentPlatform) == address(0)) return 0;
        uint256 reserve = nameAgentPlatform.getAdvancedRequestDeposit(_NAME_GEN_SUBCOMMITTEE_SIZE);
        uint256 reward = prophecyCore.llmInferenceCostPerAgent() * _NAME_GEN_SUBCOMMITTEE_SIZE;
        return reserve + reward;
    }

    /// @dev Dispatch the AI event name generation request for a newly created event.
    function _requestEventNameGeneration(
        uint256 eventId,
        string calldata marketName,
        bytes calldata eventContext
    ) internal {
        if (address(nameAgentPlatform) == address(0)) return;

        string memory prompt;
        if (eventContext.length > 0) {
            string memory nameGenCtx = abi.decode(eventContext, (string));
            prompt = bytes(nameGenCtx).length > 0
                ? string.concat("Event: ", marketName, "\n", nameGenCtx)
                : string.concat("Event: ", marketName);
        } else {
            prompt = string.concat("Event: ", marketName);
        }
        string[] memory opts = new string[](0);
        bytes memory request = abi.encodeWithSelector(IAgent.inferString.selector, prompt, nameGenPrompt, false, opts);

        uint256 deposit = getNameGenCost();
        uint256 requestId = nameAgentPlatform.createAdvancedRequest{ value: deposit }(
            NAME_GEN_AGENT_ID,
            address(this),
            this.handleResponse.selector,
            request,
            _NAME_GEN_SUBCOMMITTEE_SIZE,
            1, // threshold
            ConsensusType.Majority,
            _NAME_GEN_TIMEOUT
        );

        _nameRequestToEvent[requestId] = eventId;
        emit EventNameGenRequested(eventId, requestId);
    }

    /// @notice Callback from the agent platform with the generated event name.
    function handleResponse(
        uint256 requestId,
        AgentResponse[] memory responses,
        ResponseStatus status,
        AgentRequest memory /* details */
    ) external nonReentrant {
        if (msg.sender != address(nameAgentPlatform)) revert NameGenAgentPlatformOnly();
        uint256 successIdx;
        bool foundSuccessfulResponse;
        for (uint256 i; i < responses.length; i++) {
            if (responses[i].status == ResponseStatus.Success) {
                successIdx = i;
                foundSuccessfulResponse = true;
                break;
            }
        }
        uint256 receiptId =
            foundSuccessfulResponse ? responses[successIdx].receipt : (responses.length > 0 ? responses[0].receipt : 0);
        emit NameGenCallbackReceived(requestId, uint8(status), receiptId);
        uint256 eventId = _nameRequestToEvent[requestId];
        if (eventId == 0) {
            emit NameGenUnmappedRequest(requestId);
            return;
        }
        delete _nameRequestToEvent[requestId];

        if (status != ResponseStatus.Success || !foundSuccessfulResponse) {
            emit EventNameGenFailed(eventId, requestId, 1, uint8(status));
            prophecyCore.completeEventNaming(eventId);
            return;
        }

        string memory generated = abi.decode(responses[successIdx].result, (string));
        if (bytes(generated).length == 0) {
            emit EventNameGenFailed(eventId, requestId, 2, uint8(status));
            prophecyCore.completeEventNaming(eventId);
            return;
        }

        prophecyCore.setGeneratedEventName(eventId, generated);
        emit EventNameGenCompleted(eventId, generated);
    }

    /// @dev Maps event key => packed subscriber value => 1-indexed position in _eventSubscribers[key].
    /// Used for O(1) swap-and-pop removal when markets leave their resolution window.
    mapping(bytes32 => mapping(uint256 => uint256)) internal _eventSubscriberIndex;

    /// @dev Overflow redirect mappings for batched resolution schedule processing.
    /// When a batch exceeds _SCHEDULE_BATCH_SIZE, remaining entries stay in the original
    /// array and these mappings redirect the overflow callback to the source timestamp.
    mapping(uint256 => uint256) internal _overflowSubscribeSourceTs;
    mapping(uint256 => uint256) internal _overflowUnsubscribeSourceTs;

    // --- V16 appended fields (name gen) ---
    IHttpSingletonSomniaAgents public nameAgentPlatform;
    mapping(uint256 => uint256) internal _nameRequestToEvent; // requestId -> eventId
    string public nameGenPrompt; // system prompt for AI name generation
    mapping(uint256 => string) internal _deprecated_pendingGeneratedName; // deprecated: no longer used

    uint256[43] private __gap;
}

Other files

  • contracts/lib/MarketDataLib.sol
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.30;
    
    import { MarketLocal, LogicalOperator } from "../types/OnChainEventTypes.sol";
    
    library MarketDataLib {
        function initMarketLocal(
            MarketLocal storage ml,
            uint256 resolutionStartTs,
            uint256 resolutionEndTs,
            LogicalOperator groupsLogicalOp
        ) internal {
            ml.resolutionStartTs = resolutionStartTs;
            ml.resolutionEndTs = resolutionEndTs;
            ml.groupsLogicalOp = groupsLogicalOp;
        }
    }
    
  • contracts/lib/ConditionEval.sol
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.30;
    
    import {
        ConditionGroup,
        InternalCondition,
        Operator,
        ParamType,
        LogicalOperator
    } from "../types/OnChainEventTypes.sol";
    
    error InvalidIndexedParamIndex();
    error InvalidOperatorForType();
    
    library ConditionEval {
        /**
         * @dev Decodes a bytes32 parameter from raw event data at a given offset.
         */
        function decodeBytes32Param(
            bytes calldata _data,
            uint256 _offset
        ) internal pure returns (bytes32 value) {
            if (_data.length < _offset + 32) {
                return bytes32(0);
            }
            assembly ("memory-safe") {
                value := calldataload(add(_data.offset, _offset))
            }
        }
    
        /**
         * @dev Decodes a string parameter from raw event data.
         */
        function decodeStringParam(
            bytes calldata _data,
            uint256 _paramDataOffset
        ) internal pure returns (string memory) {
            bytes32 stringOffsetPointer = decodeBytes32Param(_data, _paramDataOffset);
            uint256 relativeOffset = uint256(stringOffsetPointer);
            if (relativeOffset + 32 > _data.length) {
                return "";
            }
            uint256 stringLength;
            assembly ("memory-safe") {
                stringLength := calldataload(add(_data.offset, relativeOffset))
            }
            if (relativeOffset + 32 + stringLength > _data.length) {
                return "";
            }
            bytes memory decodedBytes = new bytes(stringLength);
            uint256 destPtr;
            uint256 srcPtr;
            assembly ("memory-safe") {
                destPtr := add(decodedBytes, 0x20)
                srcPtr := add(add(_data.offset, relativeOffset), 0x20)
                calldatacopy(destPtr, srcPtr, stringLength)
            }
            return string(decodedBytes);
        }
    
        /**
         * @dev Evaluates a single, specific condition by decoding the parameter value from raw event data and comparing it.
         * @param ic The internal condition to evaluate.
         * @param eventTopics An array of event topics (including indexed parameters).
         * @param data The ABI-encoded data payload of the event (non-indexed parameters).
         * @return True if the condition is met.
         */
        function evalCond(
            InternalCondition memory ic,
            bytes32[] calldata eventTopics,
            bytes calldata data
        ) internal pure returns (bool) {
            // For non-indexed params, paramIndex is the 0-based index of the param *amongst non-indexed params*.
            // For indexed params, paramIndex is the index in the topics array (1, 2, or 3).
            bytes32 got;
            if (ic.isIndexed) {
                if (ic.paramIndex == 0 || ic.paramIndex >= eventTopics.length) revert InvalidIndexedParamIndex();
                got = eventTopics[ic.paramIndex];
            } else {
                if (ic.paramType == ParamType.STRING) {
                    // For strings, we decode, hash, and then compare.
                    string memory strValue = decodeStringParam(data, ic.paramIndex * 32);
                    bytes32 a = keccak256(bytes(strValue));
                    bytes32 b = ic.value;
                    if (ic.op == Operator.EQ) return a == b;
                    if (ic.op == Operator.NEQ) return a != b;
                    return false; // Other operators invalid for string
                } else {
                    got = decodeBytes32Param(data, ic.paramIndex * 32);
                }
            }
    
            if (ic.paramType == ParamType.UINT) {
                uint256 gotUint = uint256(got);
                uint256 expUint = uint256(ic.value);
                if (ic.op == Operator.EQ) return gotUint == expUint;
                if (ic.op == Operator.NEQ) return gotUint != expUint;
                if (ic.op == Operator.GT) return gotUint > expUint;
                if (ic.op == Operator.GTE) return gotUint >= expUint;
                if (ic.op == Operator.LT) return gotUint < expUint;
                if (ic.op == Operator.LTE) return gotUint <= expUint;
            } else if (ic.paramType == ParamType.INT) {
                int256 gotInt = int256(uint256(got));
                int256 exp = int256(uint256(ic.value));
                if (ic.op == Operator.EQ) return gotInt == exp;
                if (ic.op == Operator.NEQ) return gotInt != exp;
                if (ic.op == Operator.GT) return gotInt > exp;
                if (ic.op == Operator.GTE) return gotInt >= exp;
                if (ic.op == Operator.LT) return gotInt < exp;
                if (ic.op == Operator.LTE) return gotInt <= exp;
            } else if (ic.paramType == ParamType.BOOL) {
                bool gotBool = int256(uint256(got)) != 0;
                bool exp = int256(uint256(ic.value)) != 0;
                if (ic.op == Operator.EQ) return gotBool == exp;
                if (ic.op == Operator.NEQ) return gotBool != exp;
            } else if (ic.paramType == ParamType.ADDRESS) {
                address gotAddr = address(uint160(uint256(got)));
                address exp = address(uint160(uint256(ic.value)));
                if (ic.op == Operator.EQ) return gotAddr == exp;
                if (ic.op == Operator.NEQ) return gotAddr != exp;
            } else if (ic.paramType == ParamType.BYTES32) {
                bytes32 exp = ic.value;
                if (ic.op == Operator.EQ) return got == exp;
                if (ic.op == Operator.NEQ) return got != exp;
            }
            return false;
        }
    
        /**
         * @dev Evaluates all conditions within a group against the raw event data.
         * @param cg The condition group to evaluate.
         * @param eventTopics The array of event topics.
         * @param data The ABI-encoded data payload of the event.
         * @return True if the group's conditions are met by the event.
         */
        function evalGroup(
            ConditionGroup memory cg,
            bytes32[] calldata eventTopics,
            bytes calldata data
        ) internal pure returns (bool) {
            if (cg.conditions.length == 0) return true;
    
            bool res = (cg.logicalOp == LogicalOperator.AND);
    
            for (uint256 i = 0; i < cg.conditions.length; i++) {
                InternalCondition memory ic = cg.conditions[i];
    
                bool cr = evalCond(ic, eventTopics, data);
    
                if (cg.logicalOp == LogicalOperator.AND) {
                    res = res && cr;
                    if (!res) return false;
                } else {
                    res = res || cr;
                    if (res) return true;
                }
            }
            return res;
        }
    
        /**
         * @dev Checks whether an event is "relevant" to a condition group for seenCount purposes.
         * If relevanceMask is 0, all events are relevant (backwards compatible).
         * Otherwise, only conditions whose bit is set in the mask must pass.
         * @param cg The condition group (in memory).
         * @param eventTopics The array of event topics.
         * @param data The ABI-encoded data payload of the event.
         * @return True if the event is relevant to this group.
         */
        function evalRelevance(
            ConditionGroup memory cg,
            bytes32[] calldata eventTopics,
            bytes calldata data
        ) internal pure returns (bool) {
            if (cg.relevanceMask == 0) return true;
    
            uint256 len = cg.conditions.length;
            for (uint256 i; i < len; i++) {
                if (cg.relevanceMask & (1 << i) != 0) {
                    if (!evalCond(cg.conditions[i], eventTopics, data)) {
                        return false;
                    }
                }
            }
            return true;
        }
    
        function parseOp(
            string calldata op,
            ParamType paramType
        ) internal pure returns (Operator) {
            bytes32 k = keccak256(bytes(op));
            if (k == keccak256("==")) return Operator.EQ;
            if (k == keccak256("!=")) return Operator.NEQ;
            if (k == keccak256(">")) {
                if (paramType != ParamType.INT && paramType != ParamType.UINT) revert InvalidOperatorForType();
                return Operator.GT;
            }
            if (k == keccak256(">=")) {
                if (paramType != ParamType.INT && paramType != ParamType.UINT) revert InvalidOperatorForType();
                return Operator.GTE;
            }
            if (k == keccak256("<")) {
                if (paramType != ParamType.INT && paramType != ParamType.UINT) revert InvalidOperatorForType();
                return Operator.LT;
            }
            if (k == keccak256("<=")) {
                if (paramType != ParamType.INT && paramType != ParamType.UINT) revert InvalidOperatorForType();
                return Operator.LTE;
            }
            revert InvalidOperatorForType();
        }
    }
    
  • contracts/lib/LiquidityLib.sol
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.30;
    
    interface IProphecyCoreNext {
        function DEFAULT_INITIAL_LIQUIDITY_BASE() external view returns (uint256);
    }
    
    library LiquidityLib {
        function computeInitialLiquidity(
            address prophecyCoreAddr,
            uint256 initialLiquidityBase
        ) internal view returns (uint256 usedBase, uint256 initialLiquidity) {
            usedBase = initialLiquidityBase;
            if (usedBase == 0) {
                usedBase = defaultInitialLiquidityBase(prophecyCoreAddr);
            }
            initialLiquidity = usedBase;
        }
    
        function defaultInitialLiquidityBase(
            address prophecyCoreAddr
        ) internal view returns (uint256) {
            try IProphecyCoreNext(prophecyCoreAddr).DEFAULT_INITIAL_LIQUIDITY_BASE() returns (uint256 v) {
                return v;
            } catch {
                return 10_000;
            }
        }
    }
    
  • contracts/interfaces/IModerationStrategy.sol
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.30;
    
    /// @title IModerationStrategy
    /// @notice Interface for pluggable event moderation strategies.
    /// Implementations are notified when an event is created and must call back
    /// `ProphecyCore.approveEvent()` or `ProphecyCore.rejectEvent()`.
    interface IModerationStrategy {
        /// @notice Called by ProphecyCore when a new event is created while moderation is active.
        /// @param eventId The ProphecyCore event ID.
        /// @param name The event name (the question being moderated).
        /// @param eventContext ABI-encoded context for moderation (e.g. resolution prompt + string options).
        /// @dev msg.value contains the moderation deposit to be forwarded to the agent platform.
        function onEventCreated(
            uint256 eventId,
            string calldata name,
            bytes calldata eventContext
        ) external payable;
    
        /// @notice Returns the cost required for moderation.
        /// @return The moderation cost in wei that must be sent with onEventCreated().
        function getModerationCost() external view returns (uint256);
    }
    
  • contracts/interfaces/IProphecyCore.sol
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.30;
    
    import { IProphecySettlement } from "./IProphecySettlement.sol";
    import { IVenueRegistry } from "./IVenueRegistry.sol";
    import { IModerationStrategy } from "./IModerationStrategy.sol";
    
    enum ResolverType {
        NONE,
        ON_CHAIN,
        AI,
        CREATOR,
        MULTI_OUTCOME
    }
    
    /// @notice Moderation status for a market.
    enum ModerationStatus {
        None, // 0 — no moderation required (default, backwards-compatible)
        Pending, // 1 — awaiting moderation decision, not yet tradeable
        Approved, // 2 — moderation passed, tradeable
        Rejected // 3 — moderation failed, market voided, permanently untradeable
    }
    
    /// @notice Lifecycle status for a market.
    enum MarketStatus {
        PENDING, // 0 — pre-market tasks incomplete
        ACTIVE, // 1 — tasks complete, trading open (or ready to open)
        CLOSED, // 2 — trading window ended, awaiting resolution
        RESOLVED, // 3 — outcome determined (YES/NO)
        VOIDED, // 4 — voided (outcome=2)
        SETTLED // 5 — settlement finalized
    }
    
    /// @notice Trade action IDs used in the TradePermit EIP-712 signature.
    enum TradeAction {
        BUY_YES, // 0
        BUY_NO, // 1
        SELL_YES, // 2
        SELL_NO, // 3
        ADD_LIQUIDITY, // 4
        REMOVE_LIQUIDITY, // 5
        ADD_LIQUIDITY_FROM_SHARES, // 6
        REMOVE_LIQUIDITY_TO_SHARES // 7
    }
    
    /// @title IProphecyCore
    /// @notice Interface for the core Prophecy CPMM prediction market contract.
    /// Handles market registration, trading, liquidity provision, and settlement preparation.
    interface IProphecyCore {
        // =========================================================================
        // Structs
        // =========================================================================
    
        /// @notice Core on-chain state for a single binary prediction market.
        struct MarketCore {
            uint256 tradingStartTs;
            uint256 tradingEndTs;
            uint256 resolutionStartTs;
            uint256 resolutionEndTs;
            address creator;
            address resolver; // market implementation (registering contract)
            address stakeToken; // address(0) native
            bool resolved;
            uint8 outcome; // 0=NO, 1=YES, 2=VOIDED
            uint256 totalYesShares;
            uint256 totalNoShares;
            uint256 totalShares; // sum of the above
            uint256 participantCount; // unique traders (holding any shares or traded at least once)
            uint256 initialLiquidityBase; // initial liquidity in base units (wei for native token)
            uint256 feeBps; // per-market LP trading fee in basis points (locked at creation from protocol)
        }
    
        /// @notice A user's share position in a market.
        struct SharePosition {
            uint256 yes;
            uint256 no;
            bool claimed;
        }
    
        /// @notice Parameters for registering a new market via a resolver contract.
        /// @dev Venue signature verification is handled by the calling resolver, not ProphecyCore.
        ///      venueSignature and deadline are kept for frontend compatibility but ignored by ProphecyCore.
        struct MarketRegistrationParams {
            string name;
            uint256 venueId;
            bytes venueSignature;
            address creator;
            address stakeToken;
            uint256 tradingStartTs;
            uint256 tradingEndTs;
            uint256 resolutionStartTs;
            uint256 resolutionEndTs;
            uint256 initialLiquidityBase;
            uint8 noMatchOutcome; // 0=NO, 2=VOIDED - what happens if no resolution event
            uint8 resolverType; // must match the resolver's ResolverType (1=ON_CHAIN, 2=AI, 3=CREATOR)
            uint256 deadline;
        }
    
        // =========================================================================
        // Events
        // =========================================================================
    
        event MarketEventCreated(uint256 indexed eventId, string name, address indexed resolver);
    
        event MarketRegistered(
            uint256 indexed marketId,
            address indexed creator,
            address stakeToken,
            string name,
            uint256 venueId,
            uint256 openTs,
            uint256 closeTs,
            uint256 resolutionStartTs,
            uint256 resolutionEndTs,
            uint256 initialLiquidity,
            address resolverOrigin,
            ResolverType resolverType
        );
    
        event MarketRegisteredV2(
            uint256 indexed marketId,
            address indexed creator,
            address stakeToken,
            string name,
            uint256 venueId,
            uint256 openTs,
            uint256 closeTs,
            uint256 resolutionStartTs,
            uint256 resolutionEndTs,
            uint256 initialLiquidity,
            address resolverOrigin,
            ResolverType resolverType,
            uint256 indexed eventId
        );
        event MarketResolved(uint256 indexed marketId, uint8 outcome);
        event MarketNameGenerated(uint256 indexed marketId, string generatedName);
        event MarketComputedNameSet(uint256 indexed marketId, string computedName);
        event EventNameGenerated(uint256 indexed eventId, string generatedName);
        event WinningsClaimed(uint256 indexed marketId, address indexed user, uint256 payout);
        // CPMM specific
        event Trade(
            uint256 indexed marketId,
            address indexed trader,
            bool indexed sideYes,
            bool isBuy,
            uint256 tokenAmount,
            uint256 shareAmount,
            uint256 fee
        );
        /// @notice Emitted after every trade with updated raw pool reserves.
        event PriceChange(uint256 indexed marketId, uint256 yesPool, uint256 noPool);
    
        event MarketRegistrationRejected(uint256 indexed venueId, address indexed creator, string reason);
        event VenueTradeFeeClaimed(uint256 indexed venueId, address indexed owner, address stakeToken, uint256 amount);
        event ModerationStrategySet(address indexed strategy);
        event EventPendingModeration(uint256 indexed eventId, address indexed strategy);
        event EventModerationApproved(uint256 indexed eventId);
        event EventModerationRejected(uint256 indexed eventId, string reason);
    
        // Pre-market readiness events
        event EventTaskCompleted(uint256 indexed eventId, uint256 taskBit);
        event EventReady(uint256 indexed eventId);
        event EventTaskDeadlineExpired(uint256 indexed eventId);
    
        // Market lifecycle events
        event MarketStatusChanged(uint256 indexed marketId, MarketStatus indexed status);
    
        // Agent cost events
        event LLMInferenceCostPerAgentSet(uint256 cost);
        event WebFetchCostPerAgentSet(uint256 cost);
        event ModerationCommitteeSizeSet(uint256 size);
    
        // =========================================================================
        // Custom Errors
        // =========================================================================
    
        /// @notice Thrown when the caller is not a whitelisted resolver contract.
        error NotResolver();
    
        /// @notice Thrown when the caller is not the settlement contract.
        error NotSettlement();
    
        /// @notice Thrown when the supplied market ID does not correspond to an existing market.
        error MarketNotFound();
    
        /// @notice Thrown when a native-token operation is called with msg.value == 0.
        error NoValueSent();
    
        /// @notice Thrown when a required amount parameter is zero.
        error ZeroAmount();
    
        /// @notice Thrown when a required address parameter is the zero address.
        error ZeroAddress();
    
        /// @notice Thrown when a native token transfer fails.
        error TransferFailed();
    
        /// @notice Thrown when the market name is an empty string.
        error EmptyName();
    
        /// @notice Thrown when tradingStartTs is not in the future.
        error TradingStartInPast();
    
        /// @notice Thrown when tradingEndTs <= tradingStartTs.
        error InvalidTradingWindow();
    
        /// @notice Thrown when resolutionStartTs < tradingEndTs.
        error InvalidResolutionStart();
    
        /// @notice Thrown when resolutionEndTs <= resolutionStartTs.
        error InvalidResolutionEnd();
    
        /// @notice Thrown when the resolution window is shorter than the minimum.
        error ResolutionWindowTooShort();
    
        /// @notice Thrown when an EIP-712 permit has expired.
        error PermitExpired();
    
        /// @notice Thrown when noMatchOutcome is neither 0 (NO) nor 2 (VOIDED).
        error InvalidNoMatchOutcome();
    
        /// @notice Thrown when msg.value does not match the required initial liquidity for native-token markets.
        error IncorrectValue();
    
        /// @notice Thrown when msg.value > 0 for an ERC20-staked operation.
        error NativeNotExpected();
    
        /// @notice Thrown when the sum of creator + LP + venue reward rates exceeds 100 %.
        error ExcessiveRake();
    
        /// @notice Thrown when the pool has not been initialized (both reserves are zero).
        error PoolNotInitialized();
    
        /// @notice Thrown when a liquidity deposit is too small to mint any LP shares.
        error DepositTooSmall();
    
        /// @notice Thrown when the output amount or shares fall below the caller's minimum.
        error SlippageExceeded();
    
        /// @notice Thrown on a buy whose effective price (amountIn / sharesOut) exceeds 1.
        /// @dev Each winning share redeems for at most 1 stake (minus rake), so paying
        ///      more than 1 stake per share is objectively irrational regardless of
        ///      outcome prediction. Catches the thin-pool footgun where fees and
        ///      slippage combine to push the per-share cost above par. See review #10.
        error EffectivePriceAbovePar();
    
        /// @notice Thrown when the caller does not hold enough shares or LP tokens.
        error InsufficientBalance();
    
        /// @notice Thrown when reducing extracted collateral would underflow.
        error ExtractedCollateralUnderflow();
    
        /// @notice Thrown when an operation is attempted on an already-finalized market.
        error MarketFinalized();
    
        /// @notice Thrown when there are no LP shares, so no liquidity exists for trading.
        error NoLiquidity();
    
        /// @notice Thrown when the combined LP + venue fee exceeds the caller's maxFeeBps.
        error ExcessiveFees();
    
        /// @notice Thrown when trading is attempted outside the trading window.
        error MarketClosed();
    
        /// @notice Thrown when an action requires the market to be resolved but it is not.
        error NotResolved();
    
        /// @notice Thrown when the settlement contract address has not been configured.
        error SettlementNotSet();
    
        /// @notice Thrown when a user attempts to claim winnings that have already been claimed.
        error AlreadyClaimed();
    
        /// @notice Thrown when amountIn is non-zero for a native-token buy (should use msg.value).
        error UnexpectedAmountParam();
    
        /// @notice Thrown when a payout transfer to the recipient fails.
        error PayoutFailed();
    
        /// @notice Thrown when the resolverType in params does not match the resolver's registered type.
        error ResolverTypeMismatch();
    
        /// @notice Thrown when the supplied eventId does not exist.
        error EventNotFound();
    
        /// @notice Thrown when the caller is not the resolver that created the event.
        error EventResolverMismatch();
    
        /// @notice Thrown when there are no pending fees or rewards to claim.
        error NothingToClaim();
    
        /// @notice Thrown when the caller is not the venue owner.
        error NotVenueOwner();
    
        /// @notice Thrown when the caller is not the moderation strategy.
        error NotModerator();
    
        /// @notice Thrown when a market's event is pending moderation or rejected.
        error EventNotApproved();
    
        /// @notice Thrown when the event's pre-market task deadline has expired.
        error EventDeadlineExpired();
    
        /// @notice Thrown when the event's pre-market tasks are not yet complete.
        error EventNotReady();
    
        /// @notice Thrown when trying to void an event that is already ready.
        error EventAlreadyReady();
    
        /// @notice Thrown when trying to void an event whose deadline has not expired.
        error DeadlineNotExpired();
    
        /// @notice Thrown when setting a deadline that is not in the future.
        error DeadlineInPast();
    
        /// @notice Thrown when a moderation action targets a non-pending market.
        error NotPendingModeration();
    
        // =========================================================================
        // Market Registration
        // =========================================================================
    
        /// @notice Called by a whitelisted resolver to register a new prediction market.
        /// @param params The market registration parameters including name, timing, and stake token.
        /// @param resolver The address of the resolver contract that will determine the outcome.
        /// @return marketId The unique identifier assigned to the newly created market.
        /// @dev Reverts with `EmptyName` if `params.name` is empty.
        /// @dev Reverts with `TradingStartInPast` if `params.tradingStartTs <= block.timestamp`.
        /// @dev Reverts with `InvalidTradingWindow` if `params.tradingEndTs <= params.tradingStartTs`.
        /// @dev Reverts with `InvalidResolutionStart` if `params.resolutionStartTs < params.tradingEndTs`.
        /// @dev Reverts with `InvalidResolutionEnd` if `params.resolutionEndTs <= params.resolutionStartTs`.
        /// @dev Reverts with `InvalidNoMatchOutcome` if `params.noMatchOutcome` is not 0 or 2.
        /// @dev Reverts with `IncorrectValue` if native-token msg.value does not match initial liquidity.
        /// @dev Reverts with `NativeNotExpected` if msg.value > 0 for an ERC20-staked market.
        /// @dev Reverts with `ExcessiveRake` if creator + LP + venue reward rates exceed 100 %.
        /// @dev Reverts with "Venue inactive" if the venue is not active.
        /// @dev Reverts with "Invalid signature" if the venue permit signature is invalid.
        function registerMarket(
            MarketRegistrationParams calldata params,
            address resolver,
            address resolverOrigin,
            uint256 eventId,
            bytes calldata eventContext
        ) external payable returns (uint256);
    
        /// @notice Create a new market event. Only callable by whitelisted resolvers.
        /// @param name Human-readable name for the event (the "question").
        /// @param eventContext ABI-encoded context for name generation and moderation.
        /// @return eventId The unique identifier assigned to the newly created event.
        /// @dev If moderation is enabled, msg.value is forwarded as the moderation deposit.
        function createMarketEvent(
            string calldata name,
            bytes calldata eventContext
        ) external payable returns (uint256 eventId);
    
        /// @notice Return all market IDs belonging to an event.
        /// @param eventId The event to query.
        /// @return marketIds The array of market IDs in the event.
        function getEventMarkets(
            uint256 eventId
        ) external view returns (uint256[] memory marketIds);
    
        // =========================================================================
        // CPMM Trading
        // =========================================================================
    
        /// @notice Buy YES shares by depositing tokens into the pool.
        /// @param marketId The market to trade on.
        /// @param amountIn Token amount to spend (ignored for native-token markets; use msg.value).
        /// @param minSharesOut Minimum shares to receive (slippage protection).
        /// @param maxFeeBps Maximum acceptable total fee in basis points.
        /// @param venueId Venue through which the trade is routed.
        /// @param signature EIP-712 trade permit signed by the venue signer.
        /// @return sharesOut The number of YES shares received.
        /// @dev Reverts with `MarketNotFound` if the market does not exist.
        /// @dev Reverts with `MarketClosed` if trading is outside the open window.
        /// @dev Reverts with `MarketFinalized` if the market has been finalized.
        /// @dev Reverts with `ZeroAmount` if the effective amount is zero.
        /// @dev Reverts with `NoLiquidity` if there are no LP shares.
        /// @dev Reverts with `ExcessiveFees` if LP + venue fee exceeds `maxFeeBps`.
        /// @dev Reverts with `SlippageExceeded` if `sharesOut < minSharesOut`.
        /// @dev Reverts with `NoValueSent` if native-token market and msg.value == 0.
        /// @dev Reverts with `NativeNotExpected` if ERC20 market and msg.value > 0.
        /// @dev Reverts with `PayoutFailed` if the venue fee transfer fails.
        /// @dev Reverts with "Venue inactive" if the venue is not active.
        /// @dev Reverts with "Invalid signature" if the trade permit is invalid.
        function buyYes(
            uint256 marketId,
            uint256 amountIn,
            uint256 minSharesOut,
            uint256 maxFeeBps,
            uint256 venueId,
            uint256 deadline,
            bytes calldata signature
        ) external payable returns (uint256 sharesOut);
    
        /// @notice Buy NO shares by depositing tokens into the pool.
        /// @param marketId The market to trade on.
        /// @param amountIn Token amount to spend (ignored for native-token markets; use msg.value).
        /// @param minSharesOut Minimum shares to receive (slippage protection).
        /// @param maxFeeBps Maximum acceptable total fee in basis points.
        /// @param venueId Venue through which the trade is routed.
        /// @param signature EIP-712 trade permit signed by the venue signer.
        /// @return sharesOut The number of NO shares received.
        /// @dev Reverts with `MarketNotFound` if the market does not exist.
        /// @dev Reverts with `MarketClosed` if trading is outside the open window.
        /// @dev Reverts with `MarketFinalized` if the market has been finalized.
        /// @dev Reverts with `ZeroAmount` if the effective amount is zero.
        /// @dev Reverts with `NoLiquidity` if there are no LP shares.
        /// @dev Reverts with `ExcessiveFees` if LP + venue fee exceeds `maxFeeBps`.
        /// @dev Reverts with `SlippageExceeded` if `sharesOut < minSharesOut`.
        /// @dev Reverts with `NoValueSent` if native-token market and msg.value == 0.
        /// @dev Reverts with `NativeNotExpected` if ERC20 market and msg.value > 0.
        /// @dev Reverts with `PayoutFailed` if the venue fee transfer fails.
        /// @dev Reverts with "Venue inactive" if the venue is not active.
        /// @dev Reverts with "Invalid signature" if the trade permit is invalid.
        function buyNo(
            uint256 marketId,
            uint256 amountIn,
            uint256 minSharesOut,
            uint256 maxFeeBps,
            uint256 venueId,
            uint256 deadline,
            bytes calldata signature
        ) external payable returns (uint256 sharesOut);
    
        /// @notice Sell YES shares to withdraw tokens from the pool.
        /// @param marketId The market to trade on.
        /// @param sharesIn Number of YES shares to sell.
        /// @param minAmountOut Minimum token amount to receive (slippage protection).
        /// @param maxFeeBps Maximum acceptable total fee in basis points.
        /// @param venueId Venue through which the trade is routed.
        /// @param signature EIP-712 trade permit signed by the venue signer.
        /// @return amountOut The token amount received after fees.
        /// @dev Reverts with `MarketNotFound` if the market does not exist.
        /// @dev Reverts with `MarketClosed` if trading is outside the open window.
        /// @dev Reverts with `MarketFinalized` if the market has been finalized.
        /// @dev Reverts with `ZeroAmount` if sharesIn is zero.
        /// @dev Reverts with `NoLiquidity` if there are no LP shares.
        /// @dev Reverts with `InsufficientBalance` if the caller does not hold enough YES shares.
        /// @dev Reverts with `ExcessiveFees` if LP + venue fee exceeds `maxFeeBps`.
        /// @dev Reverts with `SlippageExceeded` if `amountOut < minAmountOut`.
        /// @dev Reverts with "Venue inactive" if the venue is not active.
        /// @dev Reverts with "Invalid signature" if the trade permit is invalid.
        function sellYes(
            uint256 marketId,
            uint256 sharesIn,
            uint256 minAmountOut,
            uint256 maxFeeBps,
            uint256 venueId,
            uint256 deadline,
            bytes calldata signature
        ) external returns (uint256 amountOut);
    
        /// @notice Sell NO shares to withdraw tokens from the pool.
        /// @param marketId The market to trade on.
        /// @param sharesIn Number of NO shares to sell.
        /// @param minAmountOut Minimum token amount to receive (slippage protection).
        /// @param maxFeeBps Maximum acceptable total fee in basis points.
        /// @param venueId Venue through which the trade is routed.
        /// @param signature EIP-712 trade permit signed by the venue signer.
        /// @return amountOut The token amount received after fees.
        /// @dev Reverts with `MarketNotFound` if the market does not exist.
        /// @dev Reverts with `MarketClosed` if trading is outside the open window.
        /// @dev Reverts with `MarketFinalized` if the market has been finalized.
        /// @dev Reverts with `ZeroAmount` if sharesIn is zero.
        /// @dev Reverts with `NoLiquidity` if there are no LP shares.
        /// @dev Reverts with `InsufficientBalance` if the caller does not hold enough NO shares.
        /// @dev Reverts with `ExcessiveFees` if LP + venue fee exceeds `maxFeeBps`.
        /// @dev Reverts with `SlippageExceeded` if `amountOut < minAmountOut`.
        /// @dev Reverts with "Venue inactive" if the venue is not active.
        /// @dev Reverts with "Invalid signature" if the trade permit is invalid.
        function sellNo(
            uint256 marketId,
            uint256 sharesIn,
            uint256 minAmountOut,
            uint256 maxFeeBps,
            uint256 venueId,
            uint256 deadline,
            bytes calldata signature
        ) external returns (uint256 amountOut);
    
        // =========================================================================
        // Liquidity
        // =========================================================================
    
        /// @notice Add liquidity from stake tokens. Mints LP shares proportional to the deposit.
        /// @param marketId The market to add liquidity to.
        /// @param amountIn Token amount to deposit (ignored for native-token markets; use msg.value).
        /// @param minLpSharesOut Minimum LP shares to receive (slippage protection).
        /// @param venueId Venue for trade permit verification.
        /// @param signature EIP-712 trade permit signed by the venue signer.
        /// @return lpSharesMinted The number of LP shares minted.
        /// @dev Reverts with `MarketNotFound` if the market does not exist.
        /// @dev Reverts with `MarketClosed` if the market is outside the trading window.
        /// @dev Reverts with `MarketFinalized` if the market has been finalized.
        /// @dev Reverts with `ZeroAmount` if the effective amount is zero.
        /// @dev Reverts with `PoolNotInitialized` if the pool has no reserves.
        /// @dev Reverts with `DepositTooSmall` if no LP shares would be minted.
        /// @dev Reverts with `SlippageExceeded` if `lpSharesMinted < minLpSharesOut`.
        /// @dev Reverts with `NoValueSent` if native-token market and msg.value == 0.
        /// @dev Reverts with `NativeNotExpected` if ERC20 market and msg.value > 0.
        /// @dev Reverts with "Venue inactive" if the venue is not active.
        /// @dev Reverts with "Invalid signature" if the trade permit is invalid.
        function addLiquidity(
            uint256 marketId,
            uint256 amountIn,
            uint256 minLpSharesOut,
            uint256 venueId,
            uint256 deadline,
            bytes calldata signature
        ) external payable returns (uint256 lpSharesMinted);
    
        /// @notice Remove liquidity to receive stake tokens back. Burns LP shares.
        /// @param marketId The market to remove liquidity from.
        /// @param lpSharesAmount Number of LP shares to burn.
        /// @param minAmountOut Minimum token amount to receive (slippage protection).
        /// @param venueId Venue for trade permit verification.
        /// @param signature EIP-712 trade permit signed by the venue signer.
        /// @return amountOut The token amount withdrawn.
        /// @dev Reverts with `MarketNotFound` if the market does not exist.
        /// @dev Reverts with `MarketClosed` if the market is outside the trading window.
        /// @dev Reverts with `MarketFinalized` if the market has been finalized.
        /// @dev Reverts with `ZeroAmount` if lpSharesAmount is zero.
        /// @dev Reverts with `InsufficientBalance` if the caller does not hold enough LP shares.
        /// @dev Reverts with `SlippageExceeded` if `amountOut < minAmountOut`.
        /// @dev Reverts with "Venue inactive" if the venue is not active.
        /// @dev Reverts with "Invalid signature" if the trade permit is invalid.
        function removeLiquidity(
            uint256 marketId,
            uint256 lpSharesAmount,
            uint256 minAmountOut,
            uint256 venueId,
            uint256 deadline,
            bytes calldata signature
        ) external returns (uint256 amountOut);
    
        /// @notice Add liquidity by converting YES+NO share pairs into LP shares.
        /// @param marketId The market to add liquidity to.
        /// @param amount Number of share pairs to convert (1 pair = 1 YES + 1 NO).
        /// @param minLpSharesOut Minimum LP shares to receive (slippage protection).
        /// @param venueId Venue for trade permit verification.
        /// @param deadline EIP-712 permit deadline (0 = no deadline).
        /// @param signature EIP-712 trade permit signed by the venue signer.
        /// @return lpSharesMinted The number of LP shares minted.
        function addLiquidityFromShares(
            uint256 marketId,
            uint256 amount,
            uint256 minLpSharesOut,
            uint256 venueId,
            uint256 deadline,
            bytes calldata signature
        ) external returns (uint256 lpSharesMinted);
    
        /// @notice Remove liquidity to receive YES and NO shares instead of stake tokens.
        /// @param marketId The market to remove liquidity from.
        /// @param lpSharesAmount Number of LP shares to burn.
        /// @param minYesOut Minimum YES shares to receive (slippage protection).
        /// @param minNoOut Minimum NO shares to receive (slippage protection).
        /// @param venueId Venue for trade permit verification.
        /// @param deadline EIP-712 permit deadline (0 = no deadline).
        /// @param signature EIP-712 trade permit signed by the venue signer.
        /// @return yesOut The number of YES shares received.
        /// @return noOut The number of NO shares received.
        function removeLiquidityToShares(
            uint256 marketId,
            uint256 lpSharesAmount,
            uint256 minYesOut,
            uint256 minNoOut,
            uint256 venueId,
            uint256 deadline,
            bytes calldata signature
        ) external returns (uint256 yesOut, uint256 noOut);
    
        // =========================================================================
        // Quote Helpers
        // =========================================================================
    
        /// @notice Simulate a buy without executing it.
        /// @param marketId The market to quote.
        /// @param amountIn Token amount to spend.
        /// @param yesSide True to quote YES shares, false for NO.
        /// @param venueId Venue whose fee rate is included in the calculation.
        /// @return sharesOut Estimated shares received.
        /// @return fee Total fee that would be deducted.
        function quoteBuy(
            uint256 marketId,
            uint256 amountIn,
            bool yesSide,
            uint256 venueId
        ) external view returns (uint256 sharesOut, uint256 fee);
    
        /// @notice Simulate a sell without executing it.
        /// @param marketId The market to quote.
        /// @param sharesIn Number of shares to sell.
        /// @param yesSide True to quote selling YES shares, false for NO.
        /// @param venueId Venue whose fee rate is included in the calculation.
        /// @return amountOutNet Estimated token amount after fees.
        /// @return fee Total fee that would be deducted.
        function quoteSell(
            uint256 marketId,
            uint256 sharesIn,
            bool yesSide,
            uint256 venueId
        ) external view returns (uint256 amountOutNet, uint256 fee);
    
        // =========================================================================
        // Views
        // =========================================================================
    
        /// @notice Return core state and name for a market. Lazily resolves if the resolution window has passed.
        /// @param marketId The market to query.
        /// @return core The market's core state struct.
        /// @return name The market's human-readable name.
        /// @dev Reverts with `MarketNotFound` if the market does not exist.
        function getMarketCore(
            uint256 marketId
        ) external view returns (MarketCore memory core, string memory name);
    
        /// @notice Return a user's YES/NO share position for a market.
        /// @param marketId The market to query.
        /// @param user The address to look up.
        /// @return position The user's share position.
        function getUserPosition(
            uint256 marketId,
            address user
        ) external view returns (SharePosition memory position);
    
        /// @notice Return the current YES and NO pool reserves for a market.
        /// @param marketId The market to query.
        /// @return yesPool The current YES pool reserve.
        /// @return noPool The current NO pool reserve.
        function getCurrentReserves(
            uint256 marketId
        ) external view returns (uint256 yesPool, uint256 noPool);
    
        /// @notice Claim accrued venue trading fees (pull pattern).
        /// @param venueId The venue whose accumulated fees to claim.
        /// @param stakeToken The token address (address(0) for native).
        /// @return amount The amount claimed.
        /// @dev Reverts with `NotVenueOwner` if the caller is not the venue owner.
        /// @dev Reverts with `NothingToClaim` if there are no pending fees.
        function claimVenueTradeFees(
            uint256 venueId,
            address stakeToken
        ) external returns (uint256 amount);
    
        /// @notice Claim accrued LP trading fees for a market.
        /// @param marketId The market to claim fees from.
        /// @return amount The fee amount claimed.
        /// @dev Reverts with `NothingToClaim` if the caller has no pending fees.
        function claimLPFees(
            uint256 marketId
        ) external returns (uint256 amount);
    
        /// @notice Return the pending (unclaimed) LP trading fees for a user.
        /// @param marketId The market to query.
        /// @param user The LP address to look up.
        /// @return The pending fee amount.
        function getPendingLPFees(
            uint256 marketId,
            address user
        ) external view returns (uint256);
    
        /// @notice Return the next market ID that will be assigned.
        /// @return id The next market ID.
        function nextMarketId() external view returns (uint256 id);
    
        /// @notice Return the settlement contract address.
        /// @return settlement The ProphecySettlement contract.
        function settlementContract() external view returns (IProphecySettlement settlement);
    
        /// @notice Return the venue gating (VenueRegistry) contract.
        /// @return The VenueRegistry contract used for venue permits and conditions.
        function venueGating() external view returns (IVenueRegistry);
    
        // =========================================================================
        // Moderation
        // =========================================================================
    
        /// @notice Set the global moderation strategy. address(0) disables moderation.
        /// @param strategy The moderation strategy contract address.
        function setModerationStrategy(
            address strategy
        ) external;
    
        /// @notice Returns the cost required for moderation, or 0 if no strategy is set.
        /// @return The moderation cost in wei.
        function getModerationCost() external view returns (uint256);
    
        /// @notice Called by the moderation strategy to approve a pending event.
        /// Records the ready timestamp; trading start is lazily adjusted at trade time.
        /// @param eventId The event to approve.
        function approveEvent(
            uint256 eventId
        ) external;
    
        /// @notice Called by the moderation strategy to reject a pending event.
        /// All markets in the event are voided (outcome = 2).
        /// @param eventId The event to reject.
        /// @param reason Human-readable rejection reason.
        function rejectEvent(
            uint256 eventId,
            string calldata reason
        ) external;
    
        /// @notice Set an AI-generated name for a market. Only callable by the market's resolver.
        /// @param marketId The market to update.
        /// @param _generatedName The AI-generated display name.
        function setGeneratedName(
            uint256 marketId,
            string calldata _generatedName
        ) external;
    
        /// @notice Return the AI-generated name for a market, or empty string if not yet generated.
        /// @param marketId The market to query.
        function getGeneratedName(
            uint256 marketId
        ) external view returns (string memory);
    
        /// @notice Set the computed (derived) name for a market. Only callable by allowlisted resolvers.
        /// @param marketId The market to update.
        /// @param _computedName The computed display name (e.g. "5-10", "Red or Blue").
        function setComputedName(
            uint256 marketId,
            string calldata _computedName
        ) external;
    
        /// @notice Return the computed name for a market, or empty string if not set.
        /// @param marketId The market to query.
        function getComputedName(
            uint256 marketId
        ) external view returns (string memory);
    
        /// @notice Set an AI-generated name for an event. Only callable by the event's resolver.
        /// @param eventId The event to update.
        /// @param name The AI-generated event display name.
        function setGeneratedEventName(
            uint256 eventId,
            string calldata name
        ) external;
    
        /// @notice Complete the event naming task without setting a generated name.
        ///         Used as a fallback when AI name generation fails so that the event
        ///         is not stuck in PENDING. Only callable by the event's resolver.
        /// @param eventId The event whose naming task should be marked complete.
        function completeEventNaming(
            uint256 eventId
        ) external;
    
        /// @notice Return the AI-generated event name, or empty string if not yet generated.
        /// @param eventId The event to query.
        function getGeneratedEventName(
            uint256 eventId
        ) external view returns (string memory);
    
        // =========================================================================
        // Market Status
        // =========================================================================
    
        /// @notice Return the derived lifecycle status for a market.
        /// @param marketId The market to query.
        /// @return status The current MarketStatus.
        function getMarketStatus(
            uint256 marketId
        ) external view returns (MarketStatus status);
    
        /// @notice Return derived lifecycle statuses for multiple markets.
        /// @param marketIds The markets to query.
        /// @return statuses The current MarketStatus for each market.
        function getMarketStatuses(
            uint256[] calldata marketIds
        ) external view returns (MarketStatus[] memory statuses);
    
        // =========================================================================
        // Pre-Market Readiness
        // =========================================================================
    
        /// @notice Check whether all required pre-market tasks for an event are complete.
        /// @param eventId The event to query.
        /// @return ready True if the event is ready for trading.
        function isEventReady(
            uint256 eventId
        ) external view returns (bool ready);
    
        /// @notice Set the task deadline for an event. Only callable by the event's resolver.
        /// @param eventId The event to update.
        /// @param deadline The timestamp by which all tasks must complete.
        function setEventTaskDeadline(
            uint256 eventId,
            uint256 deadline
        ) external;
    
        // =========================================================================
        // Agent Cost Parameters
        // =========================================================================
    
        /// @notice Return the cost per agent for LLM inference requests (moderation, naming).
        function llmInferenceCostPerAgent() external view returns (uint256);
    
        /// @notice Return the cost per agent for web fetch requests (resolution).
        function webFetchCostPerAgent() external view returns (uint256);
    
        /// @notice Set the cost per agent for LLM inference requests.
        /// @param cost The cost in wei per agent.
        function setLLMInferenceCostPerAgent(
            uint256 cost
        ) external;
    
        /// @notice Set the cost per agent for web fetch requests.
        /// @param cost The cost in wei per agent.
        function setWebFetchCostPerAgent(
            uint256 cost
        ) external;
    }
    
  • contracts/interfaces/IProphecySettlement.sol
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.30;
    
    /// @title IProphecySettlement
    /// @notice Interface for the Prophecy post-resolution settlement contract.
    /// Handles trader winnings, LP capital returns, creator rewards, and venue rewards.
    interface IProphecySettlement {
        // =========================================================================
        // Custom Errors
        // =========================================================================
    
        /// @notice Thrown when the caller has no winnings or rewards to claim.
        error NothingToClaim();
    
        /// @notice Thrown when the caller has already claimed for this market.
        error AlreadyClaimed();
    
        /// @notice Thrown when the caller has zero LP shares for the market.
        error NoLPShares();
    
        /// @notice Thrown when the caller is not the market creator.
        error NotCreator();
    
        /// @notice Thrown when the caller is not the venue owner.
        error NotVenueOwner();
    
        /// @notice Thrown when a payout transfer to the recipient fails.
        error PaymentFailed();
    
        /// @notice Thrown when a required amount parameter is zero.
        error ZeroAmount();
    
        /// @notice Thrown when a required address parameter is the zero address.
        error ZeroAddress();
    
        // =========================================================================
        // Functions
        // =========================================================================
    
        /// @notice Claim trader settlement from a resolved market. Caller receives their payout.
        /// @param marketId The resolved market to claim from.
        /// @return payout The token amount paid out to the caller.
        /// @dev Reverts with `NothingToClaim` if the caller has no winning shares.
        /// @dev Reverts with `AlreadyClaimed` if the caller's position was already claimed.
        /// @dev Reverts with `PaymentFailed` if the payout transfer fails.
        function claimSettlement(
            uint256 marketId
        ) external returns (uint256 payout);
    
        /// @notice Eagerly finalize settlement data for a market (idempotent).
        /// @param marketId The market to finalize.
        function finalizeMarket(
            uint256 marketId
        ) external;
    
        /// @notice Claim LP capital return, resolution rewards, and unclaimed trade-time fees.
        /// @param marketId The resolved market to claim from.
        /// @return capitalReturn The proportional LP capital returned.
        /// @return rewardAmount The proportional LP resolution reward.
        /// @dev Reverts with `AlreadyClaimed` if the LP settlement was already claimed.
        /// @dev Reverts with `NoLPShares` if the caller has no LP shares.
        function claimLPSettlement(
            uint256 marketId
        ) external returns (uint256 capitalReturn, uint256 rewardAmount);
    
        /// @notice Claim the creator's share of resolution-time rewards.
        /// @param marketId The resolved market to claim from.
        /// @return amount The creator reward amount.
        /// @dev Reverts with `AlreadyClaimed` if the creator reward was already claimed.
        /// @dev Reverts with `NotCreator` if the caller is not the market creator.
        function claimCreatorReward(
            uint256 marketId
        ) external returns (uint256 amount);
    
        /// @notice Claim the venue operator's share of resolution-time rewards.
        /// @param marketId The resolved market to claim from.
        /// @return amount The venue reward amount.
        /// @dev Reverts with `AlreadyClaimed` if the venue reward was already claimed.
        /// @dev Reverts with `NotVenueOwner` if the caller is not the venue owner.
        function claimVenueReward(
            uint256 marketId
        ) external returns (uint256 amount);
    
        /// @notice Batch-claim venue rewards across all outstanding markets for a venue.
        /// @param venueId The venue whose outstanding rewards to claim.
        /// @return totalAmount The total reward amount claimed across all markets.
        /// @dev Reverts with `NotVenueOwner` if the caller is not the venue owner.
        function claimVenueRewards(
            uint256 venueId
        ) external returns (uint256 totalAmount);
    
        /// @notice Return the list of market IDs with unclaimed venue rewards for a venue.
        /// @param venueId The venue to query.
        /// @return The array of market IDs with outstanding rewards.
        function getOutstandingVenueRewards(
            uint256 venueId
        ) external view returns (uint256[] memory);
    }
    
  • contracts/interfaces/ISomniaAgents.sol
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.30;
    
    enum ConsensusType {
        Majority,
        Threshold
    }
    
    enum ResponseStatus {
        None,
        Pending,
        Success,
        Failed,
        TimedOut
    }
    
    struct AgentResponse {
        address validator;
        bytes result;
        ResponseStatus status;
        uint256 receipt;
        uint256 timestamp;
        uint256 executionCost;
    }
    
    struct AgentRequest {
        uint256 id;
        address requester;
        address callbackAddress;
        bytes4 callbackSelector;
        address[] subcommittee;
        AgentResponse[] responses;
        uint256 responseCount;
        uint256 failureCount;
        uint256 threshold;
        uint256 createdAt;
        uint256 deadline;
        ResponseStatus status;
        ConsensusType consensusType;
        uint256 remainingBudget;
    }
    
    interface IHttpSingletonSomniaAgents {
        function createAdvancedRequest(
            uint256 agentId,
            address callbackAddress,
            bytes4 callbackSelector,
            bytes calldata payload,
            uint256 subcommitteeSize,
            uint256 threshold,
            ConsensusType consensusType,
            uint256 timeout
        ) external payable returns (uint256 requestId);
    
        function getRequestDeposit() external view returns (uint256);
        function getAdvancedRequestDeposit(
            uint256 subcommitteeSize
        ) external view returns (uint256);
    }
    
    interface IAgent {
        function ExtractANumber(
            string memory key,
            string memory description,
            uint256 min,
            uint256 max,
            string memory prompt,
            string memory url,
            bool resolveUrl,
            uint8 numPages,
            uint8 confidenceThreshold
        ) external returns (uint256);
    
        function ExtractString(
            string memory key,
            string memory description,
            string[] memory options,
            string memory prompt,
            string memory url,
            bool resolveUrl,
            uint8 numPages,
            uint8 confidenceThreshold
        ) external returns (string memory);
    
        function inferString(
            string memory prompt,
            string memory system,
            bool chainOfThought,
            string[] memory allowedValues
        ) external returns (string memory response);
    }
    
  • contracts/interfaces/ISomniaReactivity.sol
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.30;
    
    /// @notice Interface for Somnia event handlers
    interface ISomniaEventHandler {
        function onEvent(
            address emitter,
            bytes32[] calldata eventTopics,
            bytes calldata data
        ) external;
    }
    
    /// @notice Somnia Reactivity Precompile interface
    interface ISomniaReactivityPrecompile {
        /// @notice Data structure representing a subscription
        struct SubscriptionData {
            // Topic filter, use 0x0 to indicate a wildcard or unused topic
            bytes32[4] eventTopics;
            // Origin (tx.origin) filter, use address(0) to indicate a wildcard
            address origin;
            // Caller (msg.sender) filter, use address(0) to indicate a wildcard
            address caller;
            // Contract emitting the event filter, use address(0) to indicate a wildcard
            address emitter;
            // The address of the contract that will handle the event
            address handlerContractAddress;
            // The function selector in the handler contract
            bytes4 handlerFunctionSelector;
            // Extra fee per gas paid to validators to prioritize this event handling
            uint64 priorityFeePerGas;
            // Maximum fee per gas the subscriber is willing to pay (base fee + priority fee)
            uint64 maxFeePerGas;
            // Maximum gas that will be provisioned per subscription callback
            uint64 gasLimit;
            // Whether the event handling is guaranteed, i.e. moved to the next block if current is full
            bool isGuaranteed;
            // Whether multiple events can be coalesced into a single handling call per block
            bool isCoalesced;
        }
    
        // System Events that can be subscribed to
        event BlockTick(uint64 indexed blockNumber);
        event Schedule(uint256 indexed timestampMillis);
    
        /// @notice Subscribe to events matching the given filter
        function subscribe(
            SubscriptionData calldata data
        ) external returns (uint256 subscriptionId);
    
        /// @notice Unsubscribe from an existing subscription
        function unsubscribe(
            uint256 subscriptionId
        ) external;
    
        /// @notice Get subscription info
        function getSubscriptionInfo(
            uint256 subscriptionId
        ) external view returns (SubscriptionData memory, address owner);
    }
    
    /// @notice Somnia Extensions library with precompile addresses
    library SomniaExtensions {
        address constant SOMNIA_REACTIVITY_PRECOMPILE_ADDRESS = address(0x0100);
    }
    
  • contracts/interfaces/IVenueRegistry.sol
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.30;
    
    /// @title IVenueRegistry
    /// @notice Interface for the Prophecy venue gating registry. Venues control market creation
    /// access via signature verification, wallet lists, and token-balance requirements.
    interface IVenueRegistry {
        // --- Enums ---
        enum ListMode {
            NONE,
            ALLOW,
            DENY
        }
    
        // --- Events ---
        event VenueCreated(uint256 indexed venueId, address indexed owner, address signer, bool active);
        event VenueUpdated(uint256 indexed venueId, address indexed owner, address signer, bool active);
        event VenueOwnerChanged(uint256 indexed venueId, address indexed newOwner);
        event ResolverSet(address indexed resolver, bool allowed);
        event NonceConsumed(uint256 indexed venueId, address indexed user, uint256 newNonce);
        event WalletListModeSet(uint256 indexed venueId, ListMode mode);
        event WalletListUpdated(uint256 indexed venueId, address[] wallets, bool onList);
        event NftRequirementsSet(uint256 indexed venueId);
        event Erc20RequirementsSet(uint256 indexed venueId);
    
        // Fee-related events
        event VenueFeeBpsSet(uint256 indexed venueId, uint256 bps);
        event VenueRewardBpsSet(uint256 indexed venueId, uint256 bps);
    
        // =========================================================================
        // Venue Lifecycle
        // =========================================================================
    
        /// @notice Create a new venue. The caller becomes the venue owner.
        /// @param signer The address that will sign EIP-712 permits for this venue.
        /// @param active Whether the venue is immediately active.
        /// @return venueId The ID of the newly created venue.
        /// @dev Reverts with "Venue ID already exists" if the venue slot is occupied.
        function createVenue(
            address signer,
            bool active
        ) external returns (uint256 venueId);
    
        /// @notice Transfer venue ownership to a new address.
        /// @param venueId The venue to transfer.
        /// @param newOwner The new owner address.
        /// @dev Reverts with "not venue owner" if the caller is not the current owner.
        /// @dev Reverts with "zero address for new owner" if `newOwner` is address(0).
        function transferVenueOwnership(
            uint256 venueId,
            address newOwner
        ) external;
    
        /// @notice Update the signer address for a venue.
        /// @param venueId The venue to update.
        /// @param signer The new signer address.
        /// @dev Reverts with "not venue owner" if the caller is not the venue owner.
        /// @dev Reverts with "zero address for active venue" if setting a zero signer on an active venue.
        function setVenueSigner(
            uint256 venueId,
            address signer
        ) external;
    
        /// @notice Activate or deactivate a venue.
        /// @param venueId The venue to update.
        /// @param active Whether the venue should be active.
        /// @dev Reverts with "not venue owner" if the caller is not the venue owner.
        /// @dev Reverts with "zero address for active venue" if activating a venue with no signer.
        function setVenueStatus(
            uint256 venueId,
            bool active
        ) external;
    
        /// @notice Set the venue's per-trade fee rate.
        /// @param venueId The venue to update.
        /// @param bps Fee rate in basis points.
        /// @dev Reverts with "not venue owner" if the caller is not the venue owner.
        /// @dev Reverts with "exceeds max venue fee" if `bps > MAX_VENUE_FEE_BPS`.
        function setVenueFeeBps(
            uint256 venueId,
            uint256 bps
        ) external;
    
        /// @notice Set the venue's resolution-time reward rate.
        /// @param venueId The venue to update.
        /// @param bps Reward rate in basis points.
        /// @dev Reverts with "not venue owner" if the caller is not the venue owner.
        /// @dev Reverts with "exceeds max venue reward" if `bps > MAX_VENUE_REWARD_BPS`.
        function setVenueRewardBps(
            uint256 venueId,
            uint256 bps
        ) external;
    
        // =========================================================================
        // Signature Verification
        // =========================================================================
    
        /// @notice Generic signature consumer. Verifies an EIP-712 permit and increments the nonce.
        /// @param venueId The venue whose signer is expected.
        /// @param user The user on whose behalf the permit is consumed.
        /// @param structHash The EIP-712 struct hash (caller is responsible for including the nonce).
        /// @param signature The EIP-712 signature bytes.
        /// @dev Reverts with "not resolver" if the caller is not a whitelisted resolver.
        /// @dev Reverts with "Venue inactive" if the venue is not active.
        /// @dev Reverts with "Invalid signature" if the recovered signer does not match.
        /// @dev Reverts with "Conditions not met" if on-chain conditions fail.
        function consumeGenericPermit(
            uint256 venueId,
            address user,
            bytes32 structHash,
            bytes calldata signature
        ) external;
    
        // =========================================================================
        // Views
        // =========================================================================
    
        /// @notice Get the current permit nonce for a (venue, user) pair.
        /// @param venueId The venue.
        /// @param user The user address.
        /// @return nonce The current nonce (auto-increments on each consumed permit).
        function getNonce(
            uint256 venueId,
            address user
        ) external view returns (uint256 nonce);
    
        /// @notice Returns the venue's trading fee rate in basis points.
        /// @param venueId The venue to query.
        /// @return bps The fee rate.
        function getVenueFeeBps(
            uint256 venueId
        ) external view returns (uint256 bps);
    
        /// @notice Returns the venue's resolution-time reward rate in basis points.
        /// @param venueId The venue to query.
        /// @return bps The reward rate.
        function getVenueRewardBps(
            uint256 venueId
        ) external view returns (uint256 bps);
    
        /// @notice Returns the venue's owner address (fee recipient).
        /// @param venueId The venue to query.
        /// @return owner The owner address.
        function getVenueOwner(
            uint256 venueId
        ) external view returns (address owner);
    }
    
  • contracts/lib/ConditionBuilderLib.sol
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.30;
    
    import {
        SingleCondition,
        ConditionInput,
        ConditionGroup,
        ParamType,
        LogicalOperator,
        InternalCondition
    } from "../types/OnChainEventTypes.sol";
    import { ConditionEval } from "./ConditionEval.sol";
    
    library ConditionBuilderLib {
        error InvalidAbsenceOutcome();
        error StringCannotBeIndexed();
    
        /// @dev Populate a ConditionGroup in storage from a ConditionInput.
        /// @return maxParamIndex maximum paramIndex encountered (for diagnostics)
        function populateGroup(
            ConditionGroup storage cg,
            ConditionInput calldata input
        ) internal returns (uint256 maxParamIndex) {
            cg.contractAddr = input.contractAddr;
            cg.eventSignature = input.eventSignature;
            cg.logicalOp = input.logicalOp;
            cg.occurrenceType = input.occurrenceType;
            cg.occurrenceValue = input.occurrenceValue;
            if (input.absenceOutcome != 0 && input.absenceOutcome != 2) revert InvalidAbsenceOutcome();
            cg.absenceOutcome = input.absenceOutcome;
            cg.relevanceMask = input.relevanceMask;
            cg.maxRelevantEvents = input.maxRelevantEvents;
    
            for (uint256 i; i < input.conditions.length; i++) {
                SingleCondition calldata sc = input.conditions[i];
                if (sc.paramIndex > maxParamIndex) {
                    maxParamIndex = sc.paramIndex;
                }
                if (sc.paramType == ParamType.STRING) {
                    if (sc.isIndexed) revert StringCannotBeIndexed();
                }
                cg.conditions
                    .push(
                        InternalCondition({
                            paramIndex: sc.paramIndex,
                            op: ConditionEval.parseOp(sc.operatorStr, sc.paramType),
                            paramType: sc.paramType,
                            value: sc.value,
                            isIndexed: sc.isIndexed
                        })
                    );
            }
            cg.maxParamIndexInGroup = maxParamIndex;
        }
    }
    
  • contracts/lib/OutcomeEvalLib.sol
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.30;
    
    import { ConditionGroup, LogicalOperator, OccurrenceType, MarketLocal } from "../types/OnChainEventTypes.sol";
    
    library OutcomeEvalLib {
        function isGroupSatisfied(
            ConditionGroup storage cg
        ) internal view returns (bool) {
            if (cg.failed) return false;
            if (cg.occurrenceType == OccurrenceType.NEVER) {
                return (cg.passCount == 0);
            } else if (cg.occurrenceType == OccurrenceType.AT_LEAST_ONCE) {
                return (cg.passCount >= 1);
            } else if (cg.occurrenceType == OccurrenceType.EXACTLY) {
                return (cg.passCount == cg.occurrenceValue);
            } else if (cg.occurrenceType == OccurrenceType.AT_LEAST) {
                return (cg.passCount >= cg.occurrenceValue);
            } else if (cg.occurrenceType == OccurrenceType.AT_MOST) {
                return (cg.passCount <= cg.occurrenceValue);
            }
            return false;
        }
    
        function finalOutcome(
            MarketLocal storage ml,
            mapping(uint256 => ConditionGroup) storage groups
        ) internal view returns (bool) {
            uint256 total = ml.totalConditionGroups;
            if (total == 0) return false; // no groups => false
            if (ml.groupsLogicalOp == LogicalOperator.AND) {
                for (uint256 i = 0; i < total; i++) {
                    if (!isGroupSatisfied(groups[i])) return false;
                }
                return true;
            } else {
                for (uint256 i = 0; i < total; i++) {
                    if (isGroupSatisfied(groups[i])) return true;
                }
                return false;
            }
        }
    
        /// @notice Tri-state outcome evaluation: returns 0 (NO), 1 (YES), or 2 (VOIDED).
        /// @dev VOIDED is returned when the market is explicitly voided, or when an absent group has absenceOutcome=2.
        function finalOutcomeTriState(
            MarketLocal storage ml,
            mapping(uint256 => ConditionGroup) storage groups,
            bool marketVoided
        ) internal view returns (uint8) {
            if (marketVoided) return 2;
    
            bool satisfied = finalOutcome(ml, groups);
    
            // If outcome was determined during event processing, skip absence check
            if (ml.conditionsSatisfied) {
                return satisfied ? uint8(1) : uint8(0);
            }
    
            // Check for absence-triggered VOID
            uint256 total = ml.totalConditionGroups;
            for (uint256 i = 0; i < total; i++) {
                ConditionGroup storage cg = groups[i];
                if (!isGroupSatisfied(cg) && _isAbsent(cg) && cg.absenceOutcome == 2) {
                    return 2;
                }
            }
    
            return satisfied ? uint8(1) : uint8(0);
        }
    
        /// @dev Returns true if the group's event source is absent (not enough events seen).
        function _isAbsent(
            ConditionGroup storage cg
        ) internal view returns (bool) {
            if (cg.failed) return false;
            if (cg.occurrenceType == OccurrenceType.NEVER || cg.occurrenceType == OccurrenceType.AT_MOST) {
                return false; // satisfied with 0 events, never absent
            }
            uint256 required = cg.occurrenceType == OccurrenceType.AT_LEAST_ONCE ? 1 : cg.occurrenceValue;
            return cg.seenCount < required;
        }
    
        function shouldStopProcessing(
            MarketLocal storage ml,
            mapping(uint256 => ConditionGroup) storage groups
        ) internal view returns (bool) {
            bool allSatisfied = true;
            bool oneSatisfied = false;
            bool allFailed = true;
            bool oneFailed = false;
    
            for (uint256 i = 0; i < ml.totalConditionGroups; i++) {
                ConditionGroup storage cg = groups[i];
                bool satisfiedEarly =
                    (cg.satisfiedEarly
                        && (cg.occurrenceType == OccurrenceType.AT_LEAST_ONCE
                            || cg.occurrenceType == OccurrenceType.AT_LEAST));
    
                if (!satisfiedEarly) allSatisfied = false;
                if (satisfiedEarly) oneSatisfied = true;
                if (!cg.failed) allFailed = false;
                if (cg.failed) oneFailed = true;
            }
    
            if (ml.groupsLogicalOp == LogicalOperator.AND) {
                return (oneFailed || allSatisfied);
            } else {
                return (oneSatisfied || allFailed);
            }
        }
    }
    
  • contracts/lib/SomniaEventHandler.sol
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.30;
    
    import { ISomniaEventHandler, SomniaExtensions } from "../interfaces/ISomniaReactivity.sol";
    
    error OnlyReactivityPrecompile();
    
    /// @notice Interface for ERC165
    interface IERC165 {
        function supportsInterface(
            bytes4 interfaceId
        ) external view returns (bool);
    }
    
    /// @notice Abstract smart contract implementing native on-chain reactivity safely with reduced boilerplate
    /// @dev The _onEvent virtual method must be overriden to define logic executed when subscription callbacks are invoked by the chain
    /// @dev The contract is deemed upgrade safe due to the absense of storage variables
    abstract contract SomniaEventHandler is IERC165, ISomniaEventHandler {
        /// @inheritdoc ISomniaEventHandler
        function onEvent(
            address emitter,
            bytes32[] calldata eventTopics,
            bytes calldata data
        ) external override {
            // Ensure only privileged execution is permitted since the receiving contract may execute its own side effects i.e. releasing prize money
            if (msg.sender != SomniaExtensions.SOMNIA_REACTIVITY_PRECOMPILE_ADDRESS) revert OnlyReactivityPrecompile();
            _onEvent(emitter, eventTopics, data);
        }
    
        /**
         * @dev Implementing contract must override to define what logic it wants to execute for subscription callbacks
         * @param emitter Smart contract that emitted the EVM event log
         * @param eventTopics List of event topics associated with the event (event signature being first param)
         * @param data Event data for non-indexed event arguments. May be empty if event only has indexed params
         */
        function _onEvent(
            address emitter,
            bytes32[] calldata eventTopics,
            bytes calldata data
        ) internal virtual;
    
        /// @dev Allows the Somnia reactivity precompile to reason about support for reactivity subscriptions
        function supportsInterface(
            bytes4 interfaceId
        ) external pure override returns (bool) {
            return type(IERC165).interfaceId == interfaceId || type(ISomniaEventHandler).interfaceId == interfaceId;
        }
    }
    
  • contracts/lib/VenuePermitLib.sol
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.30;
    
    import { IVenueRegistry } from "../interfaces/IVenueRegistry.sol";
    
    /// @title VenuePermitLib
    /// @notice Shared library for EIP-712 venue permit verification during market creation.
    /// @dev Each resolver calls this to verify the venue signature before creating markets.
    ///      The struct hash uses the same CreateMarketPermit typehash across all resolvers for now;
    ///      individual resolvers may define their own typehash in the future.
    library VenuePermitLib {
        bytes32 internal constant CREATE_MARKET_PERMIT_TYPEHASH = keccak256(
            "CreateMarketPermit(string name,uint256 venueId,uint256 tradingStartTs,uint256 tradingEndTs,uint256 resolutionStartTs,uint256 resolutionEndTs,address stakeToken,uint256 initialLiquidityBase,uint8 noMatchOutcome,uint8 resolverType,address creator,uint256 nonce,uint256 deadline)"
        );
    
        error PermitExpired();
        error VenueZeroNotAllowed();
    
        /// @notice Verify a venue signature for market creation and consume the nonce.
        /// @param venueGating The VenueRegistry contract.
        /// @param name Market name.
        /// @param venueId Venue ID.
        /// @param venueSignature EIP-712 signature from the venue signer.
        /// @param creator The market creator address.
        /// @param stakeToken The stake token address.
        /// @param tradingStartTs Trading start timestamp.
        /// @param tradingEndTs Trading end timestamp.
        /// @param resolutionStartTs Resolution start timestamp.
        /// @param resolutionEndTs Resolution end timestamp.
        /// @param initialLiquidityBase Initial liquidity base amount.
        /// @param noMatchOutcome Outcome if no resolution event (0=NO, 2=VOIDED).
        /// @param resolverType Resolver type enum value.
        /// @param deadline EIP-712 permit deadline (0 = no deadline).
        function verifyCreateMarketPermit(
            IVenueRegistry venueGating,
            string memory name,
            uint256 venueId,
            bytes memory venueSignature,
            address creator,
            address stakeToken,
            uint256 tradingStartTs,
            uint256 tradingEndTs,
            uint256 resolutionStartTs,
            uint256 resolutionEndTs,
            uint256 initialLiquidityBase,
            uint8 noMatchOutcome,
            uint8 resolverType,
            uint256 deadline
        ) internal {
            if (venueId == 0) revert VenueZeroNotAllowed();
            if (deadline != 0 && block.timestamp > deadline) revert PermitExpired();
            uint256 nonce = venueGating.getNonce(venueId, creator);
            bytes32 structHash = keccak256(
                abi.encode(
                    CREATE_MARKET_PERMIT_TYPEHASH,
                    keccak256(bytes(name)),
                    venueId,
                    tradingStartTs,
                    tradingEndTs,
                    resolutionStartTs,
                    resolutionEndTs,
                    stakeToken,
                    initialLiquidityBase,
                    noMatchOutcome,
                    resolverType,
                    creator,
                    nonce,
                    deadline
                )
            );
            venueGating.consumeGenericPermit(venueId, creator, structHash, venueSignature);
        }
    }
    
  • contracts/types/OnChainEventTypes.sol
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.30;
    
    // Shared enums and structs for OnChainEventMarket and related contracts.
    
    enum Operator {
        EQ,
        NEQ,
        GT,
        GTE,
        LT,
        LTE
    }
    
    enum LogicalOperator {
        AND,
        OR
    }
    
    enum ParamType {
        UINT,
        INT,
        BOOL,
        ADDRESS,
        BYTES32,
        STRING
    }
    
    // Occurrence requirement types for condition groups
    enum OccurrenceType {
        AT_LEAST_ONCE,
        NEVER,
        EXACTLY,
        AT_LEAST,
        AT_MOST
    }
    
    struct SingleCondition {
        uint256 paramIndex;
        string operatorStr;
        ParamType paramType;
        bytes32 value;
        bool isIndexed;
    }
    
    struct ConditionInput {
        address contractAddr;
        string eventSignature;
        SingleCondition[] conditions; // optional parameter-level filters (AND/OR over them depending on logicalOp)
        LogicalOperator logicalOp; // how to combine SingleCondition entries
        OccurrenceType occurrenceType; // required occurrence constraint
        uint256 occurrenceValue; // used for EXACTLY / AT_LEAST / AT_MOST (ignored for others)
        uint8 absenceOutcome; // 0=NO, 2=VOIDED — outcome if event source is absent
        uint256 relevanceMask; // bitmask: which conditions must pass for an event to count as "seen" (0 = all events count)
        uint256 maxRelevantEvents; // 0 = unlimited; when set, group is failed once seenCount >= max without satisfaction
    }
    
    struct InternalCondition {
        uint256 paramIndex;
        Operator op;
        ParamType paramType;
        bytes32 value;
        bool isIndexed;
    }
    
    struct ConditionGroup {
        address contractAddr;
        string eventSignature;
        InternalCondition[] conditions;
        LogicalOperator logicalOp;
        OccurrenceType occurrenceType;
        uint256 occurrenceValue; // threshold for EXACTLY/AT_LEAST/AT_MOST
        uint256 passCount; // number of matching events so far
        bool satisfiedEarly; // may become true early for AT_LEAST(_ONCE)/AT_LEAST/EXACTLY
        bool failed; // permanently failed (NEVER violated, AT_MOST exceeded, EXACTLY exceeded)
        uint256 maxParamIndexInGroup;
        uint8 absenceOutcome; // 0=NO, 2=VOIDED — outcome if event source is absent
        uint256 seenCount; // relevant events dispatched to this group during resolution window
        uint256 relevanceMask; // bitmask: which conditions must pass for an event to count as "seen" (0 = all events count)
        uint256 maxRelevantEvents; // 0 = unlimited; when set, group is failed once seenCount >= max without satisfaction
    }
    
    struct EventParam {
        string name;
        ParamType paramType;
        int256 intValue;
        string strValue;
    }
    
    struct MarketLocal {
        uint256 resolutionStartTs; // cached to avoid prophecyCore roundtrip in hot path
        uint256 resolutionEndTs; // cached to avoid prophecyCore roundtrip in hot path
        uint256 totalConditionGroups;
        bool conditionsSatisfied;
        LogicalOperator groupsLogicalOp; // how to combine condition groups for final outcome
        bool subscriptionsActive; // whether event subscriptions are currently active for this market
    }
    
    struct CreateMarketParams {
        string name;
        uint256 venueId;
        bytes venueSignature; // used by OCEM for direct callers; ignored for trusted forwarders
        address stakeToken;
        uint256 tradingStartTs;
        uint256 tradingEndTs;
        uint256 resolutionStartTs;
        uint256 resolutionEndTs;
        ConditionInput[] inputs;
        LogicalOperator groupsLogicalOp;
        uint256 initialLiquidityBase;
        uint8 noMatchOutcome; // 0=NO, 2=VOIDED - what happens if no resolution event
        uint8 resolverType; // must match the resolver's ResolverType (1=ON_CHAIN, 2=AI, 3=CREATOR)
        address creator; // address(0) = use msg.sender; otherwise used if caller is trusted forwarder
        address resolver; // address(0) = direct; non-zero = upstream resolver
        uint256 deadline; // EIP-712 permit deadline (0 = no deadline); used by OCEM for direct callers
        bytes eventContext; // ABI-encoded resolver-specific context for name generation + moderation
        bool skipNameGen; // true = caller handles name generation upstream; OCEM skips its own
    }
    
    /// @dev Extended version of CreateMarketParams with eventId for multi-market events.
    struct CreateMarketParamsV2 {
        string name;
        uint256 venueId;
        bytes venueSignature;
        address stakeToken;
        uint256 tradingStartTs;
        uint256 tradingEndTs;
        uint256 resolutionStartTs;
        uint256 resolutionEndTs;
        ConditionInput[] inputs;
        LogicalOperator groupsLogicalOp;
        uint256 initialLiquidityBase;
        uint8 noMatchOutcome;
        uint8 resolverType;
        address creator;
        address resolver;
        uint256 deadline;
        uint256 eventId; // 0 = auto-create single-market event; non-zero = add to existing event
        bytes eventContext; // ABI-encoded resolver-specific context for name generation + moderation
        bool skipNameGen; // true = caller handles name generation upstream; OCEM skips its own
    }
    
  • node_modules/@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.1.0) (access/Ownable2Step.sol)
    
    pragma solidity ^0.8.20;
    
    import {OwnableUpgradeable} from "./OwnableUpgradeable.sol";
    import {Initializable} from "../proxy/utils/Initializable.sol";
    
    /**
     * @dev Contract module which provides access control mechanism, where
     * there is an account (an owner) that can be granted exclusive access to
     * specific functions.
     *
     * This extension of the {Ownable} contract includes a two-step mechanism to transfer
     * ownership, where the new owner must call {acceptOwnership} in order to replace the
     * old one. This can help prevent common mistakes, such as transfers of ownership to
     * incorrect accounts, or to contracts that are unable to interact with the
     * permission system.
     *
     * The initial owner is specified at deployment time in the constructor for `Ownable`. This
     * can later be changed with {transferOwnership} and {acceptOwnership}.
     *
     * This module is used through inheritance. It will make available all functions
     * from parent (Ownable).
     */
    abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {
        /// @custom:storage-location erc7201:openzeppelin.storage.Ownable2Step
        struct Ownable2StepStorage {
            address _pendingOwner;
        }
    
        // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable2Step")) - 1)) & ~bytes32(uint256(0xff))
        bytes32 private constant Ownable2StepStorageLocation = 0x237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00;
    
        function _getOwnable2StepStorage() private pure returns (Ownable2StepStorage storage $) {
            assembly {
                $.slot := Ownable2StepStorageLocation
            }
        }
    
        event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
    
        function __Ownable2Step_init() internal onlyInitializing {
        }
    
        function __Ownable2Step_init_unchained() internal onlyInitializing {
        }
        /**
         * @dev Returns the address of the pending owner.
         */
        function pendingOwner() public view virtual returns (address) {
            Ownable2StepStorage storage $ = _getOwnable2StepStorage();
            return $._pendingOwner;
        }
    
        /**
         * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
         * Can only be called by the current owner.
         *
         * Setting `newOwner` to the zero address is allowed; this can be used to cancel an initiated ownership transfer.
         */
        function transferOwnership(address newOwner) public virtual override onlyOwner {
            Ownable2StepStorage storage $ = _getOwnable2StepStorage();
            $._pendingOwner = newOwner;
            emit OwnershipTransferStarted(owner(), newOwner);
        }
    
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
         * Internal function without access restriction.
         */
        function _transferOwnership(address newOwner) internal virtual override {
            Ownable2StepStorage storage $ = _getOwnable2StepStorage();
            delete $._pendingOwner;
            super._transferOwnership(newOwner);
        }
    
        /**
         * @dev The new owner accepts the ownership transfer.
         */
        function acceptOwnership() public virtual {
            address sender = _msgSender();
            if (pendingOwner() != sender) {
                revert OwnableUnauthorizedAccount(sender);
            }
            _transferOwnership(sender);
        }
    }
    
  • node_modules/@openzeppelin/contracts/utils/StorageSlot.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
    // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
    
    pragma solidity ^0.8.20;
    
    /**
     * @dev Library for reading and writing primitive types to specific storage slots.
     *
     * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
     * This library helps with reading and writing to such slots without the need for inline assembly.
     *
     * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
     *
     * Example usage to set ERC-1967 implementation slot:
     * ```solidity
     * contract ERC1967 {
     *     // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
     *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
     *
     *     function _getImplementation() internal view returns (address) {
     *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
     *     }
     *
     *     function _setImplementation(address newImplementation) internal {
     *         require(newImplementation.code.length > 0);
     *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
     *     }
     * }
     * ```
     *
     * TIP: Consider using this library along with {SlotDerivation}.
     */
    library StorageSlot {
        struct AddressSlot {
            address value;
        }
    
        struct BooleanSlot {
            bool value;
        }
    
        struct Bytes32Slot {
            bytes32 value;
        }
    
        struct Uint256Slot {
            uint256 value;
        }
    
        struct Int256Slot {
            int256 value;
        }
    
        struct StringSlot {
            string value;
        }
    
        struct BytesSlot {
            bytes value;
        }
    
        /**
         * @dev Returns an `AddressSlot` with member `value` located at `slot`.
         */
        function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
            assembly ("memory-safe") {
                r.slot := slot
            }
        }
    
        /**
         * @dev Returns a `BooleanSlot` with member `value` located at `slot`.
         */
        function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
            assembly ("memory-safe") {
                r.slot := slot
            }
        }
    
        /**
         * @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
         */
        function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
            assembly ("memory-safe") {
                r.slot := slot
            }
        }
    
        /**
         * @dev Returns a `Uint256Slot` with member `value` located at `slot`.
         */
        function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
            assembly ("memory-safe") {
                r.slot := slot
            }
        }
    
        /**
         * @dev Returns a `Int256Slot` with member `value` located at `slot`.
         */
        function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
            assembly ("memory-safe") {
                r.slot := slot
            }
        }
    
        /**
         * @dev Returns a `StringSlot` with member `value` located at `slot`.
         */
        function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
            assembly ("memory-safe") {
                r.slot := slot
            }
        }
    
        /**
         * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
         */
        function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
            assembly ("memory-safe") {
                r.slot := store.slot
            }
        }
    
        /**
         * @dev Returns a `BytesSlot` with member `value` located at `slot`.
         */
        function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
            assembly ("memory-safe") {
                r.slot := slot
            }
        }
    
        /**
         * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
         */
        function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
            assembly ("memory-safe") {
                r.slot := store.slot
            }
        }
    }
    
  • node_modules/@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
    
    pragma solidity ^0.8.20;
    
    import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
    import {Initializable} from "../proxy/utils/Initializable.sol";
    
    /**
     * @dev Contract module which provides a basic access control mechanism, where
     * there is an account (an owner) that can be granted exclusive access to
     * specific functions.
     *
     * The initial owner is set to the address provided by the deployer. This can
     * later be changed with {transferOwnership}.
     *
     * This module is used through inheritance. It will make available the modifier
     * `onlyOwner`, which can be applied to your functions to restrict their use to
     * the owner.
     */
    abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
        /// @custom:storage-location erc7201:openzeppelin.storage.Ownable
        struct OwnableStorage {
            address _owner;
        }
    
        // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
        bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;
    
        function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
            assembly {
                $.slot := OwnableStorageLocation
            }
        }
    
        /**
         * @dev The caller account is not authorized to perform an operation.
         */
        error OwnableUnauthorizedAccount(address account);
    
        /**
         * @dev The owner is not a valid owner account. (eg. `address(0)`)
         */
        error OwnableInvalidOwner(address owner);
    
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    
        /**
         * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
         */
        function __Ownable_init(address initialOwner) internal onlyInitializing {
            __Ownable_init_unchained(initialOwner);
        }
    
        function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
            if (initialOwner == address(0)) {
                revert OwnableInvalidOwner(address(0));
            }
            _transferOwnership(initialOwner);
        }
    
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            _checkOwner();
            _;
        }
    
        /**
         * @dev Returns the address of the current owner.
         */
        function owner() public view virtual returns (address) {
            OwnableStorage storage $ = _getOwnableStorage();
            return $._owner;
        }
    
        /**
         * @dev Throws if the sender is not the owner.
         */
        function _checkOwner() internal view virtual {
            if (owner() != _msgSender()) {
                revert OwnableUnauthorizedAccount(_msgSender());
            }
        }
    
        /**
         * @dev Leaves the contract without owner. It will not be possible to call
         * `onlyOwner` functions. Can only be called by the current owner.
         *
         * NOTE: Renouncing ownership will leave the contract without an owner,
         * thereby disabling any functionality that is only available to the owner.
         */
        function renounceOwnership() public virtual onlyOwner {
            _transferOwnership(address(0));
        }
    
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         * Can only be called by the current owner.
         */
        function transferOwnership(address newOwner) public virtual onlyOwner {
            if (newOwner == address(0)) {
                revert OwnableInvalidOwner(address(0));
            }
            _transferOwnership(newOwner);
        }
    
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         * Internal function without access restriction.
         */
        function _transferOwnership(address newOwner) internal virtual {
            OwnableStorage storage $ = _getOwnableStorage();
            address oldOwner = $._owner;
            $._owner = newOwner;
            emit OwnershipTransferred(oldOwner, newOwner);
        }
    }
    
  • node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)
    
    pragma solidity ^0.8.20;
    
    /**
     * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
     * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
     * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
     * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
     *
     * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
     * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
     * case an upgrade adds a module that needs to be initialized.
     *
     * For example:
     *
     * [.hljs-theme-light.nopadding]
     * ```solidity
     * contract MyToken is ERC20Upgradeable {
     *     function initialize() initializer public {
     *         __ERC20_init("MyToken", "MTK");
     *     }
     * }
     *
     * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
     *     function initializeV2() reinitializer(2) public {
     *         __ERC20Permit_init("MyToken");
     *     }
     * }
     * ```
     *
     * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
     * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
     *
     * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
     * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
     *
     * [CAUTION]
     * ====
     * Avoid leaving a contract uninitialized.
     *
     * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
     * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
     * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
     *
     * [.hljs-theme-light.nopadding]
     * ```
     * /// @custom:oz-upgrades-unsafe-allow constructor
     * constructor() {
     *     _disableInitializers();
     * }
     * ```
     * ====
     */
    abstract contract Initializable {
        /**
         * @dev Storage of the initializable contract.
         *
         * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
         * when using with upgradeable contracts.
         *
         * @custom:storage-location erc7201:openzeppelin.storage.Initializable
         */
        struct InitializableStorage {
            /**
             * @dev Indicates that the contract has been initialized.
             */
            uint64 _initialized;
            /**
             * @dev Indicates that the contract is in the process of being initialized.
             */
            bool _initializing;
        }
    
        // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
        bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
    
        /**
         * @dev The contract is already initialized.
         */
        error InvalidInitialization();
    
        /**
         * @dev The contract is not initializing.
         */
        error NotInitializing();
    
        /**
         * @dev Triggered when the contract has been initialized or reinitialized.
         */
        event Initialized(uint64 version);
    
        /**
         * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
         * `onlyInitializing` functions can be used to initialize parent contracts.
         *
         * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
         * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
         * production.
         *
         * Emits an {Initialized} event.
         */
        modifier initializer() {
            // solhint-disable-next-line var-name-mixedcase
            InitializableStorage storage $ = _getInitializableStorage();
    
            // Cache values to avoid duplicated sloads
            bool isTopLevelCall = !$._initializing;
            uint64 initialized = $._initialized;
    
            // Allowed calls:
            // - initialSetup: the contract is not in the initializing state and no previous version was
            //                 initialized
            // - construction: the contract is initialized at version 1 (no reinitialization) and the
            //                 current contract is just being deployed
            bool initialSetup = initialized == 0 && isTopLevelCall;
            bool construction = initialized == 1 && address(this).code.length == 0;
    
            if (!initialSetup && !construction) {
                revert InvalidInitialization();
            }
            $._initialized = 1;
            if (isTopLevelCall) {
                $._initializing = true;
            }
            _;
            if (isTopLevelCall) {
                $._initializing = false;
                emit Initialized(1);
            }
        }
    
        /**
         * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
         * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
         * used to initialize parent contracts.
         *
         * A reinitializer may be used after the original initialization step. This is essential to configure modules that
         * are added through upgrades and that require initialization.
         *
         * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
         * cannot be nested. If one is invoked in the context of another, execution will revert.
         *
         * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
         * a contract, executing them in the right order is up to the developer or operator.
         *
         * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
         *
         * Emits an {Initialized} event.
         */
        modifier reinitializer(uint64 version) {
            // solhint-disable-next-line var-name-mixedcase
            InitializableStorage storage $ = _getInitializableStorage();
    
            if ($._initializing || $._initialized >= version) {
                revert InvalidInitialization();
            }
            $._initialized = version;
            $._initializing = true;
            _;
            $._initializing = false;
            emit Initialized(version);
        }
    
        /**
         * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
         * {initializer} and {reinitializer} modifiers, directly or indirectly.
         */
        modifier onlyInitializing() {
            _checkInitializing();
            _;
        }
    
        /**
         * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
         */
        function _checkInitializing() internal view virtual {
            if (!_isInitializing()) {
                revert NotInitializing();
            }
        }
    
        /**
         * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
         * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
         * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
         * through proxies.
         *
         * Emits an {Initialized} event the first time it is successfully executed.
         */
        function _disableInitializers() internal virtual {
            // solhint-disable-next-line var-name-mixedcase
            InitializableStorage storage $ = _getInitializableStorage();
    
            if ($._initializing) {
                revert InvalidInitialization();
            }
            if ($._initialized != type(uint64).max) {
                $._initialized = type(uint64).max;
                emit Initialized(type(uint64).max);
            }
        }
    
        /**
         * @dev Returns the highest version that has been initialized. See {reinitializer}.
         */
        function _getInitializedVersion() internal view returns (uint64) {
            return _getInitializableStorage()._initialized;
        }
    
        /**
         * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
         */
        function _isInitializing() internal view returns (bool) {
            return _getInitializableStorage()._initializing;
        }
    
        /**
         * @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.
         *
         * NOTE: Consider following the ERC-7201 formula to derive storage locations.
         */
        function _initializableStorageSlot() internal pure virtual returns (bytes32) {
            return INITIALIZABLE_STORAGE;
        }
    
        /**
         * @dev Returns a pointer to the storage namespace.
         */
        // solhint-disable-next-line var-name-mixedcase
        function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
            bytes32 slot = _initializableStorageSlot();
            assembly {
                $.slot := slot
            }
        }
    }
    
  • node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/UUPSUpgradeable.sol)
    
    pragma solidity ^0.8.22;
    
    import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
    import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
    import {Initializable} from "./Initializable.sol";
    
    /**
     * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
     * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
     *
     * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
     * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
     * `UUPSUpgradeable` with a custom implementation of upgrades.
     *
     * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
     */
    abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable {
        /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
        address private immutable __self = address(this);
    
        /**
         * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
         * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
         * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
         * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
         * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
         * during an upgrade.
         */
        string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
    
        /**
         * @dev The call is from an unauthorized context.
         */
        error UUPSUnauthorizedCallContext();
    
        /**
         * @dev The storage `slot` is unsupported as a UUID.
         */
        error UUPSUnsupportedProxiableUUID(bytes32 slot);
    
        /**
         * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
         * a proxy contract with an implementation (as defined in ERC-1967) pointing to self. This should only be the case
         * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
         * function through ERC-1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
         * fail.
         */
        modifier onlyProxy() {
            _checkProxy();
            _;
        }
    
        /**
         * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
         * callable on the implementing contract but not through proxies.
         */
        modifier notDelegated() {
            _checkNotDelegated();
            _;
        }
    
        function __UUPSUpgradeable_init() internal onlyInitializing {
        }
    
        function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
        }
        /**
         * @dev Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the
         * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
         *
         * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
         * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
         * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
         */
        function proxiableUUID() external view virtual notDelegated returns (bytes32) {
            return ERC1967Utils.IMPLEMENTATION_SLOT;
        }
    
        /**
         * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
         * encoded in `data`.
         *
         * Calls {_authorizeUpgrade}.
         *
         * Emits an {Upgraded} event.
         *
         * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
         */
        function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
            _authorizeUpgrade(newImplementation);
            _upgradeToAndCallUUPS(newImplementation, data);
        }
    
        /**
         * @dev Reverts if the execution is not performed via delegatecall or the execution
         * context is not of a proxy with an ERC-1967 compliant implementation pointing to self.
         */
        function _checkProxy() internal view virtual {
            if (
                address(this) == __self || // Must be called through delegatecall
                ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
            ) {
                revert UUPSUnauthorizedCallContext();
            }
        }
    
        /**
         * @dev Reverts if the execution is performed via delegatecall.
         * See {notDelegated}.
         */
        function _checkNotDelegated() internal view virtual {
            if (address(this) != __self) {
                // Must not be called through delegatecall
                revert UUPSUnauthorizedCallContext();
            }
        }
    
        /**
         * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
         * {upgradeToAndCall}.
         *
         * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
         *
         * ```solidity
         * function _authorizeUpgrade(address) internal onlyOwner {}
         * ```
         */
        function _authorizeUpgrade(address newImplementation) internal virtual;
    
        /**
         * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
         *
         * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
         * is expected to be the implementation slot in ERC-1967.
         *
         * Emits an {IERC1967-Upgraded} event.
         */
        function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
            try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
                    revert UUPSUnsupportedProxiableUUID(slot);
                }
                ERC1967Utils.upgradeToAndCall(newImplementation, data);
            } catch {
                // The implementation is not UUPS
                revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
            }
        }
    }
    
  • node_modules/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
    
    pragma solidity ^0.8.20;
    import {Initializable} from "../proxy/utils/Initializable.sol";
    
    /**
     * @dev Provides information about the current execution context, including the
     * sender of the transaction and its data. While these are generally available
     * via msg.sender and msg.data, they should not be accessed in such a direct
     * manner, since when dealing with meta-transactions the account sending and
     * paying for execution may not be the actual sender (as far as an application
     * is concerned).
     *
     * This contract is only required for intermediate, library-like contracts.
     */
    abstract contract ContextUpgradeable is Initializable {
        function __Context_init() internal onlyInitializing {
        }
    
        function __Context_init_unchained() internal onlyInitializing {
        }
        function _msgSender() internal view virtual returns (address) {
            return msg.sender;
        }
    
        function _msgData() internal view virtual returns (bytes calldata) {
            return msg.data;
        }
    
        function _contextSuffixLength() internal view virtual returns (uint256) {
            return 0;
        }
    }
    
  • node_modules/@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)
    
    pragma solidity ^0.8.20;
    import {Initializable} from "../proxy/utils/Initializable.sol";
    
    /**
     * @dev Contract module that helps prevent reentrant calls to a function.
     *
     * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
     * available, which can be applied to functions to make sure there are no nested
     * (reentrant) calls to them.
     *
     * Note that because there is a single `nonReentrant` guard, functions marked as
     * `nonReentrant` may not call one another. This can be worked around by making
     * those functions `private`, and then adding `external` `nonReentrant` entry
     * points to them.
     *
     * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
     * consider using {ReentrancyGuardTransient} instead.
     *
     * TIP: If you would like to learn more about reentrancy and alternative ways
     * to protect against it, check out our blog post
     * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
     */
    abstract contract ReentrancyGuardUpgradeable is Initializable {
        // Booleans are more expensive than uint256 or any type that takes up a full
        // word because each write operation emits an extra SLOAD to first read the
        // slot's contents, replace the bits taken up by the boolean, and then write
        // back. This is the compiler's defense against contract upgrades and
        // pointer aliasing, and it cannot be disabled.
    
        // The values being non-zero value makes deployment a bit more expensive,
        // but in exchange the refund on every call to nonReentrant will be lower in
        // amount. Since refunds are capped to a percentage of the total
        // transaction's gas, it is best to keep them low in cases like this one, to
        // increase the likelihood of the full refund coming into effect.
        uint256 private constant NOT_ENTERED = 1;
        uint256 private constant ENTERED = 2;
    
        /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
        struct ReentrancyGuardStorage {
            uint256 _status;
        }
    
        // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
        bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
    
        function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
            assembly {
                $.slot := ReentrancyGuardStorageLocation
            }
        }
    
        /**
         * @dev Unauthorized reentrant call.
         */
        error ReentrancyGuardReentrantCall();
    
        function __ReentrancyGuard_init() internal onlyInitializing {
            __ReentrancyGuard_init_unchained();
        }
    
        function __ReentrancyGuard_init_unchained() internal onlyInitializing {
            ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
            $._status = NOT_ENTERED;
        }
    
        /**
         * @dev Prevents a contract from calling itself, directly or indirectly.
         * Calling a `nonReentrant` function from another `nonReentrant`
         * function is not supported. It is possible to prevent this from happening
         * by making the `nonReentrant` function external, and making it call a
         * `private` function that does the actual work.
         */
        modifier nonReentrant() {
            _nonReentrantBefore();
            _;
            _nonReentrantAfter();
        }
    
        function _nonReentrantBefore() private {
            ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
            // On the first call to nonReentrant, _status will be NOT_ENTERED
            if ($._status == ENTERED) {
                revert ReentrancyGuardReentrantCall();
            }
    
            // Any calls to nonReentrant after this point will fail
            $._status = ENTERED;
        }
    
        function _nonReentrantAfter() private {
            ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
            // By storing the original value once again, a refund is triggered (see
            // https://eips.ethereum.org/EIPS/eip-2200)
            $._status = NOT_ENTERED;
        }
    
        /**
         * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
         * `nonReentrant` function in the call stack.
         */
        function _reentrancyGuardEntered() internal view returns (bool) {
            ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
            return $._status == ENTERED;
        }
    }
    
  • node_modules/@openzeppelin/contracts/interfaces/IERC1967.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1967.sol)
    
    pragma solidity >=0.4.11;
    
    /**
     * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
     */
    interface IERC1967 {
        /**
         * @dev Emitted when the implementation is upgraded.
         */
        event Upgraded(address indexed implementation);
    
        /**
         * @dev Emitted when the admin account has changed.
         */
        event AdminChanged(address previousAdmin, address newAdmin);
    
        /**
         * @dev Emitted when the beacon is changed.
         */
        event BeaconUpgraded(address indexed beacon);
    }
    
  • node_modules/@openzeppelin/contracts/interfaces/draft-IERC1822.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC1822.sol)
    
    pragma solidity >=0.4.16;
    
    /**
     * @dev ERC-1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
     * proxy whose upgrades are fully controlled by the current implementation.
     */
    interface IERC1822Proxiable {
        /**
         * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
         * address.
         *
         * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
         * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
         * function revert if invoked through a proxy.
         */
        function proxiableUUID() external view returns (bytes32);
    }
    
  • node_modules/@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.4.0) (proxy/ERC1967/ERC1967Utils.sol)
    
    pragma solidity ^0.8.21;
    
    import {IBeacon} from "../beacon/IBeacon.sol";
    import {IERC1967} from "../../interfaces/IERC1967.sol";
    import {Address} from "../../utils/Address.sol";
    import {StorageSlot} from "../../utils/StorageSlot.sol";
    
    /**
     * @dev This library provides getters and event emitting update functions for
     * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] slots.
     */
    library ERC1967Utils {
        /**
         * @dev Storage slot with the address of the current implementation.
         * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
         */
        // solhint-disable-next-line private-vars-leading-underscore
        bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
    
        /**
         * @dev The `implementation` of the proxy is invalid.
         */
        error ERC1967InvalidImplementation(address implementation);
    
        /**
         * @dev The `admin` of the proxy is invalid.
         */
        error ERC1967InvalidAdmin(address admin);
    
        /**
         * @dev The `beacon` of the proxy is invalid.
         */
        error ERC1967InvalidBeacon(address beacon);
    
        /**
         * @dev An upgrade function sees `msg.value > 0` that may be lost.
         */
        error ERC1967NonPayable();
    
        /**
         * @dev Returns the current implementation address.
         */
        function getImplementation() internal view returns (address) {
            return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
        }
    
        /**
         * @dev Stores a new address in the ERC-1967 implementation slot.
         */
        function _setImplementation(address newImplementation) private {
            if (newImplementation.code.length == 0) {
                revert ERC1967InvalidImplementation(newImplementation);
            }
            StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
        }
    
        /**
         * @dev Performs implementation upgrade with additional setup call if data is nonempty.
         * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
         * to avoid stuck value in the contract.
         *
         * Emits an {IERC1967-Upgraded} event.
         */
        function upgradeToAndCall(address newImplementation, bytes memory data) internal {
            _setImplementation(newImplementation);
            emit IERC1967.Upgraded(newImplementation);
    
            if (data.length > 0) {
                Address.functionDelegateCall(newImplementation, data);
            } else {
                _checkNonPayable();
            }
        }
    
        /**
         * @dev Storage slot with the admin of the contract.
         * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
         */
        // solhint-disable-next-line private-vars-leading-underscore
        bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
    
        /**
         * @dev Returns the current admin.
         *
         * TIP: To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using
         * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
         * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
         */
        function getAdmin() internal view returns (address) {
            return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
        }
    
        /**
         * @dev Stores a new address in the ERC-1967 admin slot.
         */
        function _setAdmin(address newAdmin) private {
            if (newAdmin == address(0)) {
                revert ERC1967InvalidAdmin(address(0));
            }
            StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
        }
    
        /**
         * @dev Changes the admin of the proxy.
         *
         * Emits an {IERC1967-AdminChanged} event.
         */
        function changeAdmin(address newAdmin) internal {
            emit IERC1967.AdminChanged(getAdmin(), newAdmin);
            _setAdmin(newAdmin);
        }
    
        /**
         * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
         * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
         */
        // solhint-disable-next-line private-vars-leading-underscore
        bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
    
        /**
         * @dev Returns the current beacon.
         */
        function getBeacon() internal view returns (address) {
            return StorageSlot.getAddressSlot(BEACON_SLOT).value;
        }
    
        /**
         * @dev Stores a new beacon in the ERC-1967 beacon slot.
         */
        function _setBeacon(address newBeacon) private {
            if (newBeacon.code.length == 0) {
                revert ERC1967InvalidBeacon(newBeacon);
            }
    
            StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
    
            address beaconImplementation = IBeacon(newBeacon).implementation();
            if (beaconImplementation.code.length == 0) {
                revert ERC1967InvalidImplementation(beaconImplementation);
            }
        }
    
        /**
         * @dev Change the beacon and trigger a setup call if data is nonempty.
         * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
         * to avoid stuck value in the contract.
         *
         * Emits an {IERC1967-BeaconUpgraded} event.
         *
         * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
         * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
         * efficiency.
         */
        function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
            _setBeacon(newBeacon);
            emit IERC1967.BeaconUpgraded(newBeacon);
    
            if (data.length > 0) {
                Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
            } else {
                _checkNonPayable();
            }
        }
    
        /**
         * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
         * if an upgrade doesn't perform an initialization call.
         */
        function _checkNonPayable() private {
            if (msg.value > 0) {
                revert ERC1967NonPayable();
            }
        }
    }
    
  • node_modules/@openzeppelin/contracts/proxy/beacon/IBeacon.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.4.0) (proxy/beacon/IBeacon.sol)
    
    pragma solidity >=0.4.16;
    
    /**
     * @dev This is the interface that {BeaconProxy} expects of its beacon.
     */
    interface IBeacon {
        /**
         * @dev Must return an address that can be used as a delegate call target.
         *
         * {UpgradeableBeacon} will check that this address is a contract.
         */
        function implementation() external view returns (address);
    }
    
  • node_modules/@openzeppelin/contracts/utils/Address.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.4.0) (utils/Address.sol)
    
    pragma solidity ^0.8.20;
    
    import {Errors} from "./Errors.sol";
    
    /**
     * @dev Collection of functions related to the address type
     */
    library Address {
        /**
         * @dev There's no code at `target` (it is not a contract).
         */
        error AddressEmptyCode(address target);
    
        /**
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
         * `recipient`, forwarding all available gas and reverting on errors.
         *
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
         * imposed by `transfer`, making them unable to receive funds via
         * `transfer`. {sendValue} removes this limitation.
         *
         * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
         *
         * IMPORTANT: because control is transferred to `recipient`, care must be
         * taken to not create reentrancy vulnerabilities. Consider using
         * {ReentrancyGuard} or the
         * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
         */
        function sendValue(address payable recipient, uint256 amount) internal {
            if (address(this).balance < amount) {
                revert Errors.InsufficientBalance(address(this).balance, amount);
            }
    
            (bool success, bytes memory returndata) = recipient.call{value: amount}("");
            if (!success) {
                _revert(returndata);
            }
        }
    
        /**
         * @dev Performs a Solidity function call using a low level `call`. A
         * plain `call` is an unsafe replacement for a function call: use this
         * function instead.
         *
         * If `target` reverts with a revert reason or custom error, it is bubbled
         * up by this function (like regular Solidity function calls). However, if
         * the call reverted with no returned reason, this function reverts with a
         * {Errors.FailedCall} error.
         *
         * Returns the raw returned data. To convert to the expected return value,
         * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
         *
         * Requirements:
         *
         * - `target` must be a contract.
         * - calling `target` with `data` must not revert.
         */
        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
            return functionCallWithValue(target, data, 0);
        }
    
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but also transferring `value` wei to `target`.
         *
         * Requirements:
         *
         * - the calling contract must have an ETH balance of at least `value`.
         * - the called Solidity function must be `payable`.
         */
        function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
            if (address(this).balance < value) {
                revert Errors.InsufficientBalance(address(this).balance, value);
            }
            (bool success, bytes memory returndata) = target.call{value: value}(data);
            return verifyCallResultFromTarget(target, success, returndata);
        }
    
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a static call.
         */
        function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
            (bool success, bytes memory returndata) = target.staticcall(data);
            return verifyCallResultFromTarget(target, success, returndata);
        }
    
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a delegate call.
         */
        function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
            (bool success, bytes memory returndata) = target.delegatecall(data);
            return verifyCallResultFromTarget(target, success, returndata);
        }
    
        /**
         * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
         * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
         * of an unsuccessful call.
         */
        function verifyCallResultFromTarget(
            address target,
            bool success,
            bytes memory returndata
        ) internal view returns (bytes memory) {
            if (!success) {
                _revert(returndata);
            } else {
                // only check if target is a contract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                if (returndata.length == 0 && target.code.length == 0) {
                    revert AddressEmptyCode(target);
                }
                return returndata;
            }
        }
    
        /**
         * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
         * revert reason or with a default {Errors.FailedCall} error.
         */
        function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
            if (!success) {
                _revert(returndata);
            } else {
                return returndata;
            }
        }
    
        /**
         * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
         */
        function _revert(bytes memory returndata) private pure {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                assembly ("memory-safe") {
                    revert(add(returndata, 0x20), mload(returndata))
                }
            } else {
                revert Errors.FailedCall();
            }
        }
    }
    
  • node_modules/@openzeppelin/contracts/utils/Errors.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)
    
    pragma solidity ^0.8.20;
    
    /**
     * @dev Collection of common custom errors used in multiple contracts
     *
     * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
     * It is recommended to avoid relying on the error API for critical functionality.
     *
     * _Available since v5.1._
     */
    library Errors {
        /**
         * @dev The ETH balance of the account is not enough to perform the operation.
         */
        error InsufficientBalance(uint256 balance, uint256 needed);
    
        /**
         * @dev A call to an address target failed. The target may have reverted.
         */
        error FailedCall();
    
        /**
         * @dev The deployment failed.
         */
        error FailedDeployment();
    
        /**
         * @dev A necessary precompile is missing.
         */
        error MissingPrecompile(address);
    }
    
ABI · 99 entries
json
[
  {
    "type": "constructor",
    "inputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "AddressEmptyCode",
    "type": "error",
    "inputs": [
      {
        "name": "target",
        "type": "address",
        "internalType": "address"
      }
    ]
  },
  {
    "name": "ERC1967InvalidImplementation",
    "type": "error",
    "inputs": [
      {
        "name": "implementation",
        "type": "address",
        "internalType": "address"
      }
    ]
  },
  {
    "name": "ERC1967NonPayable",
    "type": "error",
    "inputs": []
  },
  {
    "name": "FailedCall",
    "type": "error",
    "inputs": []
  },
  {
    "name": "IncorrectMsgValue",
    "type": "error",
    "inputs": []
  },
  {
    "name": "InvalidAbsenceOutcome",
    "type": "error",
    "inputs": []
  },
  {
    "name": "InvalidIndexedParamIndex",
    "type": "error",
    "inputs": []
  },
  {
    "name": "InvalidInitialization",
    "type": "error",
    "inputs": []
  },
  {
    "name": "InvalidOperatorForType",
    "type": "error",
    "inputs": []
  },
  {
    "name": "MarketAlreadyResolved",
    "type": "error",
    "inputs": []
  },
  {
    "name": "NameGenAgentPlatformOnly",
    "type": "error",
    "inputs": []
  },
  {
    "name": "NoGroups",
    "type": "error",
    "inputs": []
  },
  {
    "name": "NotInitializing",
    "type": "error",
    "inputs": []
  },
  {
    "name": "NotMarketResolver",
    "type": "error",
    "inputs": []
  },
  {
    "name": "OnlyReactivityPrecompile",
    "type": "error",
    "inputs": []
  },
  {
    "name": "OwnableInvalidOwner",
    "type": "error",
    "inputs": [
      {
        "name": "owner",
        "type": "address",
        "internalType": "address"
      }
    ]
  },
  {
    "name": "OwnableUnauthorizedAccount",
    "type": "error",
    "inputs": [
      {
        "name": "account",
        "type": "address",
        "internalType": "address"
      }
    ]
  },
  {
    "name": "PermitExpired",
    "type": "error",
    "inputs": []
  },
  {
    "name": "ReentrancyGuardReentrantCall",
    "type": "error",
    "inputs": []
  },
  {
    "name": "ResolutionWindowNotOpen",
    "type": "error",
    "inputs": []
  },
  {
    "name": "StringCannotBeIndexed",
    "type": "error",
    "inputs": []
  },
  {
    "name": "UUPSUnauthorizedCallContext",
    "type": "error",
    "inputs": []
  },
  {
    "name": "UUPSUnsupportedProxiableUUID",
    "type": "error",
    "inputs": [
      {
        "name": "slot",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ]
  },
  {
    "name": "UntrustedResolverOverride",
    "type": "error",
    "inputs": []
  },
  {
    "name": "VenueZeroNotAllowed",
    "type": "error",
    "inputs": []
  },
  {
    "name": "ZeroAddr",
    "type": "error",
    "inputs": []
  },
  {
    "name": "ZeroEventAddress",
    "type": "error",
    "inputs": []
  },
  {
    "name": "ZeroEventTopic",
    "type": "error",
    "inputs": []
  },
  {
    "name": "ConditionEvaluated",
    "type": "event",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "groupId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "conditionIndex",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "result",
        "type": "bool",
        "indexed": false,
        "internalType": "bool"
      }
    ],
    "anonymous": false
  },
  {
    "name": "ConditionGroupChecked",
    "type": "event",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "groupId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "matched",
        "type": "bool",
        "indexed": false,
        "internalType": "bool"
      },
      {
        "name": "passCountBefore",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "passCountAfter",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      }
    ],
    "anonymous": false
  },
  {
    "name": "ConditionGroupMatched",
    "type": "event",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "groupId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "newPassCount",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "firstSatisfaction",
        "type": "bool",
        "indexed": false,
        "internalType": "bool"
      }
    ],
    "anonymous": false
  },
  {
    "name": "ConditionGroupRegistered",
    "type": "event",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "groupId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "contractAddr",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "eventSignature",
        "type": "string",
        "indexed": false,
        "internalType": "string"
      },
      {
        "name": "condCount",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "logicalOp",
        "type": "string",
        "indexed": false,
        "internalType": "string"
      },
      {
        "name": "occurrenceType",
        "type": "uint8",
        "indexed": false,
        "internalType": "enum OccurrenceType"
      },
      {
        "name": "occurrenceValue",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      }
    ],
    "anonymous": false
  },
  {
    "name": "CreateMarket_Attempt",
    "type": "event",
    "inputs": [
      {
        "name": "sender",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "value",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      }
    ],
    "anonymous": false
  },
  {
    "name": "EventNameGenCompleted",
    "type": "event",
    "inputs": [
      {
        "name": "eventId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "generatedName",
        "type": "string",
        "indexed": false,
        "internalType": "string"
      }
    ],
    "anonymous": false
  },
  {
    "name": "EventNameGenFailed",
    "type": "event",
    "inputs": [
      {
        "name": "eventId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "requestId",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "reason",
        "type": "uint8",
        "indexed": false,
        "internalType": "uint8"
      },
      {
        "name": "status",
        "type": "uint8",
        "indexed": false,
        "internalType": "uint8"
      }
    ],
    "anonymous": false
  },
  {
    "name": "EventNameGenRequested",
    "type": "event",
    "inputs": [
      {
        "name": "eventId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "requestId",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      }
    ],
    "anonymous": false
  },
  {
    "name": "GroupEvaluated",
    "type": "event",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "groupId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "result",
        "type": "bool",
        "indexed": false,
        "internalType": "bool"
      }
    ],
    "anonymous": false
  },
  {
    "name": "GroupEvaluationSkipped",
    "type": "event",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "groupId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "reason",
        "type": "string",
        "indexed": false,
        "internalType": "string"
      }
    ],
    "anonymous": false
  },
  {
    "name": "Initialized",
    "type": "event",
    "inputs": [
      {
        "name": "version",
        "type": "uint64",
        "indexed": false,
        "internalType": "uint64"
      }
    ],
    "anonymous": false
  },
  {
    "name": "MarketCreationFailed",
    "type": "event",
    "inputs": [
      {
        "name": "venueId",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "creator",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "reason",
        "type": "string",
        "indexed": false,
        "internalType": "string"
      }
    ],
    "anonymous": false
  },
  {
    "name": "MarketResolved",
    "type": "event",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "outcome",
        "type": "uint8",
        "indexed": false,
        "internalType": "uint8"
      }
    ],
    "anonymous": false
  },
  {
    "name": "MarketVoided",
    "type": "event",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "resolver",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      }
    ],
    "anonymous": false
  },
  {
    "name": "NameGenCallbackReceived",
    "type": "event",
    "inputs": [
      {
        "name": "requestId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "status",
        "type": "uint8",
        "indexed": false,
        "internalType": "uint8"
      },
      {
        "name": "receiptId",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      }
    ],
    "anonymous": false
  },
  {
    "name": "NameGenUnmappedRequest",
    "type": "event",
    "inputs": [
      {
        "name": "requestId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      }
    ],
    "anonymous": false
  },
  {
    "name": "OCEMReactivityUnsubscribeEndSchedule",
    "type": "event",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "subscriptionId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "timestampMs",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      }
    ],
    "anonymous": false
  },
  {
    "name": "OCEMReactivityUnsubscribeSharedEndCleanup",
    "type": "event",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "subscriptionId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "timestampMs",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      }
    ],
    "anonymous": false
  },
  {
    "name": "OCEMReactivityUnsubscribeStartSchedule",
    "type": "event",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "subscriptionId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "timestampMs",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      }
    ],
    "anonymous": false
  },
  {
    "name": "OCEMReactivityUnsubscribeTopic",
    "type": "event",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "subscriptionId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "timestampMs",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "success",
        "type": "bool",
        "indexed": false,
        "internalType": "bool"
      }
    ],
    "anonymous": false
  },
  {
    "name": "OnEventNoMatchingGroups",
    "type": "event",
    "inputs": [
      {
        "name": "key",
        "type": "bytes32",
        "indexed": true,
        "internalType": "bytes32"
      }
    ],
    "anonymous": false
  },
  {
    "name": "OnEventProcessingGroup",
    "type": "event",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "groupId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      }
    ],
    "anonymous": false
  },
  {
    "name": "OnEventReceived",
    "type": "event",
    "inputs": [
      {
        "name": "source",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "eventTopic",
        "type": "bytes32",
        "indexed": true,
        "internalType": "bytes32"
      }
    ],
    "anonymous": false
  },
  {
    "name": "OwnershipTransferStarted",
    "type": "event",
    "inputs": [
      {
        "name": "previousOwner",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "newOwner",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      }
    ],
    "anonymous": false
  },
  {
    "name": "OwnershipTransferred",
    "type": "event",
    "inputs": [
      {
        "name": "previousOwner",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "newOwner",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      }
    ],
    "anonymous": false
  },
  {
    "name": "ProphecyCoreAddressUpdated",
    "type": "event",
    "inputs": [
      {
        "name": "oldAddr",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "newAddr",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      }
    ],
    "anonymous": false
  },
  {
    "name": "SettlementFinalizationFailed",
    "type": "event",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "indexed": true,
        "internalType": "uint256"
      },
      {
        "name": "reason",
        "type": "bytes",
        "indexed": false,
        "internalType": "bytes"
      }
    ],
    "anonymous": false
  },
  {
    "name": "SubscriptionCreated",
    "type": "event",
    "inputs": [
      {
        "name": "eventSource",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "subscriptionId",
        "type": "uint64",
        "indexed": false,
        "internalType": "uint64"
      }
    ],
    "anonymous": false
  },
  {
    "name": "SubscriptionEnded",
    "type": "event",
    "inputs": [
      {
        "name": "eventSource",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "subscriptionId",
        "type": "uint64",
        "indexed": false,
        "internalType": "uint64"
      }
    ],
    "anonymous": false
  },
  {
    "name": "Upgraded",
    "type": "event",
    "inputs": [
      {
        "name": "implementation",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      }
    ],
    "anonymous": false
  },
  {
    "name": "MIN_SUBSCRIPTION_BALANCE",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "NAME_GEN_AGENT_ID",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "UPGRADE_INTERFACE_VERSION",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "string",
        "internalType": "string"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "acceptOwnership",
    "type": "function",
    "inputs": [],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "allowResolver",
    "type": "function",
    "inputs": [
      {
        "name": "forwarder",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "allowed",
        "type": "bool",
        "internalType": "bool"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "conditionGroups",
    "type": "function",
    "inputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "contractAddr",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "eventSignature",
        "type": "string",
        "internalType": "string"
      },
      {
        "name": "logicalOp",
        "type": "uint8",
        "internalType": "enum LogicalOperator"
      },
      {
        "name": "occurrenceType",
        "type": "uint8",
        "internalType": "enum OccurrenceType"
      },
      {
        "name": "occurrenceValue",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "passCount",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "satisfiedEarly",
        "type": "bool",
        "internalType": "bool"
      },
      {
        "name": "failed",
        "type": "bool",
        "internalType": "bool"
      },
      {
        "name": "maxParamIndexInGroup",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "absenceOutcome",
        "type": "uint8",
        "internalType": "uint8"
      },
      {
        "name": "seenCount",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "relevanceMask",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "maxRelevantEvents",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "conditionHash",
    "type": "function",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "groupId",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "conditionIndex",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "createMarketEx",
    "type": "function",
    "inputs": [
      {
        "name": "p",
        "type": "tuple",
        "components": [
          {
            "name": "name",
            "type": "string",
            "internalType": "string"
          },
          {
            "name": "venueId",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "venueSignature",
            "type": "bytes",
            "internalType": "bytes"
          },
          {
            "name": "stakeToken",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "tradingStartTs",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "tradingEndTs",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "resolutionStartTs",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "resolutionEndTs",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "inputs",
            "type": "tuple[]",
            "components": [
              {
                "name": "contractAddr",
                "type": "address",
                "internalType": "address"
              },
              {
                "name": "eventSignature",
                "type": "string",
                "internalType": "string"
              },
              {
                "name": "conditions",
                "type": "tuple[]",
                "components": [
                  {
                    "name": "paramIndex",
                    "type": "uint256",
                    "internalType": "uint256"
                  },
                  {
                    "name": "operatorStr",
                    "type": "string",
                    "internalType": "string"
                  },
                  {
                    "name": "paramType",
                    "type": "uint8",
                    "internalType": "enum ParamType"
                  },
                  {
                    "name": "value",
                    "type": "bytes32",
                    "internalType": "bytes32"
                  },
                  {
                    "name": "isIndexed",
                    "type": "bool",
                    "internalType": "bool"
                  }
                ],
                "internalType": "struct SingleCondition[]"
              },
              {
                "name": "logicalOp",
                "type": "uint8",
                "internalType": "enum LogicalOperator"
              },
              {
                "name": "occurrenceType",
                "type": "uint8",
                "internalType": "enum OccurrenceType"
              },
              {
                "name": "occurrenceValue",
                "type": "uint256",
                "internalType": "uint256"
              },
              {
                "name": "absenceOutcome",
                "type": "uint8",
                "internalType": "uint8"
              },
              {
                "name": "relevanceMask",
                "type": "uint256",
                "internalType": "uint256"
              },
              {
                "name": "maxRelevantEvents",
                "type": "uint256",
                "internalType": "uint256"
              }
            ],
            "internalType": "struct ConditionInput[]"
          },
          {
            "name": "groupsLogicalOp",
            "type": "uint8",
            "internalType": "enum LogicalOperator"
          },
          {
            "name": "initialLiquidityBase",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "noMatchOutcome",
            "type": "uint8",
            "internalType": "uint8"
          },
          {
            "name": "resolverType",
            "type": "uint8",
            "internalType": "uint8"
          },
          {
            "name": "creator",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "resolver",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "deadline",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "eventContext",
            "type": "bytes",
            "internalType": "bytes"
          },
          {
            "name": "skipNameGen",
            "type": "bool",
            "internalType": "bool"
          }
        ],
        "internalType": "struct CreateMarketParams"
      }
    ],
    "outputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "payable"
  },
  {
    "name": "createMarketExV2",
    "type": "function",
    "inputs": [
      {
        "name": "p",
        "type": "tuple",
        "components": [
          {
            "name": "name",
            "type": "string",
            "internalType": "string"
          },
          {
            "name": "venueId",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "venueSignature",
            "type": "bytes",
            "internalType": "bytes"
          },
          {
            "name": "stakeToken",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "tradingStartTs",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "tradingEndTs",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "resolutionStartTs",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "resolutionEndTs",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "inputs",
            "type": "tuple[]",
            "components": [
              {
                "name": "contractAddr",
                "type": "address",
                "internalType": "address"
              },
              {
                "name": "eventSignature",
                "type": "string",
                "internalType": "string"
              },
              {
                "name": "conditions",
                "type": "tuple[]",
                "components": [
                  {
                    "name": "paramIndex",
                    "type": "uint256",
                    "internalType": "uint256"
                  },
                  {
                    "name": "operatorStr",
                    "type": "string",
                    "internalType": "string"
                  },
                  {
                    "name": "paramType",
                    "type": "uint8",
                    "internalType": "enum ParamType"
                  },
                  {
                    "name": "value",
                    "type": "bytes32",
                    "internalType": "bytes32"
                  },
                  {
                    "name": "isIndexed",
                    "type": "bool",
                    "internalType": "bool"
                  }
                ],
                "internalType": "struct SingleCondition[]"
              },
              {
                "name": "logicalOp",
                "type": "uint8",
                "internalType": "enum LogicalOperator"
              },
              {
                "name": "occurrenceType",
                "type": "uint8",
                "internalType": "enum OccurrenceType"
              },
              {
                "name": "occurrenceValue",
                "type": "uint256",
                "internalType": "uint256"
              },
              {
                "name": "absenceOutcome",
                "type": "uint8",
                "internalType": "uint8"
              },
              {
                "name": "relevanceMask",
                "type": "uint256",
                "internalType": "uint256"
              },
              {
                "name": "maxRelevantEvents",
                "type": "uint256",
                "internalType": "uint256"
              }
            ],
            "internalType": "struct ConditionInput[]"
          },
          {
            "name": "groupsLogicalOp",
            "type": "uint8",
            "internalType": "enum LogicalOperator"
          },
          {
            "name": "initialLiquidityBase",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "noMatchOutcome",
            "type": "uint8",
            "internalType": "uint8"
          },
          {
            "name": "resolverType",
            "type": "uint8",
            "internalType": "uint8"
          },
          {
            "name": "creator",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "resolver",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "deadline",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "eventId",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "eventContext",
            "type": "bytes",
            "internalType": "bytes"
          },
          {
            "name": "skipNameGen",
            "type": "bool",
            "internalType": "bool"
          }
        ],
        "internalType": "struct CreateMarketParamsV2"
      }
    ],
    "outputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "payable"
  },
  {
    "name": "debugGroup",
    "type": "function",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "groupId",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "contractAddr",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "eventSignature",
        "type": "string",
        "internalType": "string"
      },
      {
        "name": "condLen",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "paramIndex",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "paramType",
        "type": "uint8",
        "internalType": "enum ParamType"
      },
      {
        "name": "value",
        "type": "bytes32",
        "internalType": "bytes32"
      },
      {
        "name": "passCount",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "satisfiedEarly",
        "type": "bool",
        "internalType": "bool"
      },
      {
        "name": "failed",
        "type": "bool",
        "internalType": "bool"
      },
      {
        "name": "occurrenceType",
        "type": "uint8",
        "internalType": "enum OccurrenceType"
      },
      {
        "name": "occurrenceValue",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "absenceOutcome",
        "type": "uint8",
        "internalType": "uint8"
      },
      {
        "name": "seenCount",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getConditionGroup",
    "type": "function",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "groupId",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "contractAddr",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "eventSignature",
        "type": "string",
        "internalType": "string"
      },
      {
        "name": "conditions",
        "type": "tuple[]",
        "components": [
          {
            "name": "paramIndex",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "op",
            "type": "uint8",
            "internalType": "enum Operator"
          },
          {
            "name": "paramType",
            "type": "uint8",
            "internalType": "enum ParamType"
          },
          {
            "name": "value",
            "type": "bytes32",
            "internalType": "bytes32"
          },
          {
            "name": "isIndexed",
            "type": "bool",
            "internalType": "bool"
          }
        ],
        "internalType": "struct InternalCondition[]"
      },
      {
        "name": "logicalOp",
        "type": "uint8",
        "internalType": "enum LogicalOperator"
      },
      {
        "name": "occurrenceType",
        "type": "uint8",
        "internalType": "enum OccurrenceType"
      },
      {
        "name": "occurrenceValue",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "passCount",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "satisfiedEarly",
        "type": "bool",
        "internalType": "bool"
      },
      {
        "name": "failed",
        "type": "bool",
        "internalType": "bool"
      },
      {
        "name": "absenceOutcome",
        "type": "uint8",
        "internalType": "uint8"
      },
      {
        "name": "seenCount",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getConditions",
    "type": "function",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "groupId",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "tuple[]",
        "components": [
          {
            "name": "paramIndex",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "op",
            "type": "uint8",
            "internalType": "enum Operator"
          },
          {
            "name": "paramType",
            "type": "uint8",
            "internalType": "enum ParamType"
          },
          {
            "name": "value",
            "type": "bytes32",
            "internalType": "bytes32"
          },
          {
            "name": "isIndexed",
            "type": "bool",
            "internalType": "bool"
          }
        ],
        "internalType": "struct InternalCondition[]"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getCreateMarketCost",
    "type": "function",
    "inputs": [
      {
        "name": "initialLiquidityBase",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "stakeToken",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "skipNameGen",
        "type": "bool",
        "internalType": "bool"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getMarketConditions",
    "type": "function",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "groups",
        "type": "tuple[]",
        "components": [
          {
            "name": "contractAddr",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "eventSignature",
            "type": "string",
            "internalType": "string"
          },
          {
            "name": "conditions",
            "type": "tuple[]",
            "components": [
              {
                "name": "paramIndex",
                "type": "uint256",
                "internalType": "uint256"
              },
              {
                "name": "op",
                "type": "uint8",
                "internalType": "enum Operator"
              },
              {
                "name": "paramType",
                "type": "uint8",
                "internalType": "enum ParamType"
              },
              {
                "name": "value",
                "type": "bytes32",
                "internalType": "bytes32"
              },
              {
                "name": "isIndexed",
                "type": "bool",
                "internalType": "bool"
              }
            ],
            "internalType": "struct InternalCondition[]"
          },
          {
            "name": "logicalOp",
            "type": "uint8",
            "internalType": "enum LogicalOperator"
          },
          {
            "name": "occurrenceType",
            "type": "uint8",
            "internalType": "enum OccurrenceType"
          },
          {
            "name": "occurrenceValue",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "passCount",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "satisfiedEarly",
            "type": "bool",
            "internalType": "bool"
          },
          {
            "name": "failed",
            "type": "bool",
            "internalType": "bool"
          },
          {
            "name": "maxParamIndexInGroup",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "absenceOutcome",
            "type": "uint8",
            "internalType": "uint8"
          },
          {
            "name": "seenCount",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "relevanceMask",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "maxRelevantEvents",
            "type": "uint256",
            "internalType": "uint256"
          }
        ],
        "internalType": "struct ConditionGroup[]"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getMarketLocal",
    "type": "function",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "tuple",
        "components": [
          {
            "name": "resolutionStartTs",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "resolutionEndTs",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "totalConditionGroups",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "conditionsSatisfied",
            "type": "bool",
            "internalType": "bool"
          },
          {
            "name": "groupsLogicalOp",
            "type": "uint8",
            "internalType": "enum LogicalOperator"
          },
          {
            "name": "subscriptionsActive",
            "type": "bool",
            "internalType": "bool"
          }
        ],
        "internalType": "struct MarketLocal"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getNameGenCost",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getReactivityPrecompile",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "contract ISomniaReactivityPrecompile"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "handleResponse",
    "type": "function",
    "inputs": [
      {
        "name": "requestId",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "responses",
        "type": "tuple[]",
        "components": [
          {
            "name": "validator",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "result",
            "type": "bytes",
            "internalType": "bytes"
          },
          {
            "name": "status",
            "type": "uint8",
            "internalType": "enum ResponseStatus"
          },
          {
            "name": "receipt",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "timestamp",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "executionCost",
            "type": "uint256",
            "internalType": "uint256"
          }
        ],
        "internalType": "struct AgentResponse[]"
      },
      {
        "name": "status",
        "type": "uint8",
        "internalType": "enum ResponseStatus"
      },
      {
        "name": "",
        "type": "tuple",
        "components": [
          {
            "name": "id",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "requester",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "callbackAddress",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "callbackSelector",
            "type": "bytes4",
            "internalType": "bytes4"
          },
          {
            "name": "subcommittee",
            "type": "address[]",
            "internalType": "address[]"
          },
          {
            "name": "responses",
            "type": "tuple[]",
            "components": [
              {
                "name": "validator",
                "type": "address",
                "internalType": "address"
              },
              {
                "name": "result",
                "type": "bytes",
                "internalType": "bytes"
              },
              {
                "name": "status",
                "type": "uint8",
                "internalType": "enum ResponseStatus"
              },
              {
                "name": "receipt",
                "type": "uint256",
                "internalType": "uint256"
              },
              {
                "name": "timestamp",
                "type": "uint256",
                "internalType": "uint256"
              },
              {
                "name": "executionCost",
                "type": "uint256",
                "internalType": "uint256"
              }
            ],
            "internalType": "struct AgentResponse[]"
          },
          {
            "name": "responseCount",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "failureCount",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "threshold",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "createdAt",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "deadline",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "status",
            "type": "uint8",
            "internalType": "enum ResponseStatus"
          },
          {
            "name": "consensusType",
            "type": "uint8",
            "internalType": "enum ConsensusType"
          },
          {
            "name": "remainingBudget",
            "type": "uint256",
            "internalType": "uint256"
          }
        ],
        "internalType": "struct AgentRequest"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "initialize",
    "type": "function",
    "inputs": [
      {
        "name": "prophecyCoreAddr",
        "type": "address",
        "internalType": "contract IProphecyCore"
      },
      {
        "name": "owner",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "isMarketVoided",
    "type": "function",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "bool",
        "internalType": "bool"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "isTrustedForwarder",
    "type": "function",
    "inputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "bool",
        "internalType": "bool"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "marketData",
    "type": "function",
    "inputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "resolutionStartTs",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "resolutionEndTs",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "totalConditionGroups",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "conditionsSatisfied",
        "type": "bool",
        "internalType": "bool"
      },
      {
        "name": "groupsLogicalOp",
        "type": "uint8",
        "internalType": "enum LogicalOperator"
      },
      {
        "name": "subscriptionsActive",
        "type": "bool",
        "internalType": "bool"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "nameAgentPlatform",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "contract IHttpSingletonSomniaAgents"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "nameGenPrompt",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "string",
        "internalType": "string"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "nextLocalId",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "onEvent",
    "type": "function",
    "inputs": [
      {
        "name": "emitter",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "eventTopics",
        "type": "bytes32[]",
        "internalType": "bytes32[]"
      },
      {
        "name": "data",
        "type": "bytes",
        "internalType": "bytes"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "outcomeFor",
    "type": "function",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "outcome",
        "type": "uint8",
        "internalType": "uint8"
      },
      {
        "name": "isResolved",
        "type": "bool",
        "internalType": "bool"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "owner",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "pendingOwner",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "prophecyCore",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "contract IProphecyCore"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "proxiableUUID",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "renounceOwnership",
    "type": "function",
    "inputs": [],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "setNameAgentPlatform",
    "type": "function",
    "inputs": [
      {
        "name": "platform",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "setNameGenPrompt",
    "type": "function",
    "inputs": [
      {
        "name": "prompt",
        "type": "string",
        "internalType": "string"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "setProphecyCore",
    "type": "function",
    "inputs": [
      {
        "name": "newProphecyCore",
        "type": "address",
        "internalType": "contract IProphecyCore"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "supportsInterface",
    "type": "function",
    "inputs": [
      {
        "name": "interfaceId",
        "type": "bytes4",
        "internalType": "bytes4"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "bool",
        "internalType": "bool"
      }
    ],
    "stateMutability": "pure"
  },
  {
    "name": "transferOwnership",
    "type": "function",
    "inputs": [
      {
        "name": "newOwner",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "upgradeToAndCall",
    "type": "function",
    "inputs": [
      {
        "name": "newImplementation",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "data",
        "type": "bytes",
        "internalType": "bytes"
      }
    ],
    "outputs": [],
    "stateMutability": "payable"
  },
  {
    "name": "voidMarket",
    "type": "function",
    "inputs": [
      {
        "name": "marketId",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "type": "receive",
    "stateMutability": "payable"
  }
]