Resolvers

Resolvers are pluggable smart contracts that determine truth for specific question types. They implement a standard interface, allowing any data source - oracles, human judgment, on-chain state, or custom logic.

How Resolvers Work

Resolvers are "black boxes" from the registry's perspective. The registry doesn't care how truth is determined - only that the resolver follows the standard interface:

interface IPopResolver {
    // Called when POP is created - validate and optionally approve
    function onPopCreated(
        uint256 popId,
        uint32 templateId,
        bytes calldata payload
    ) external returns (POPState initialState);

    // Called to resolve - return ABI-encoded result
    function resolvePop(
        uint256 popId,
        address caller,
        bytes calldata payload
    ) external returns (bytes memory result);

    // Metadata functions
    function getTemplateAnswerType(uint32 templateId)
        external view returns (AnswerType);
    function getPopQuestion(uint256 popId)
        external view returns (string memory);
}

Trust Levels

Resolvers have a trust classification that affects accountability tiers:

Trust Level Description How to Get
SYSTEM Official ecosystem resolver Admin grants
VERIFIED Admin reviewed and approved Admin grants
PERMISSIONLESS Default for registered resolvers Anyone registers
NONE Not registered -

Registering a Resolver

Registration is permissionless - anyone can register a resolver contract:

// Anyone can register a resolver
registry.registerResolver(myResolverAddress);
// Resolver starts at PERMISSIONLESS trust level

// Admin can upgrade trust level
registry.setResolverTrust(myResolverAddress, ResolverTrust.VERIFIED);
// Or grant SYSTEM trust
registry.setResolverTrust(myResolverAddress, ResolverTrust.SYSTEM);

Key insight: Permissionless registration enables open innovation. Anyone can build and register resolvers. Trust is managed separately - start at PERMISSIONLESS, earn upgrades through track record.

Built-in Resolvers

Pyth Price Resolver

Oracle-based resolution using Pyth Network price feeds. Best for objective price data.

Templates:

Answer Type: BOOLEAN

// Template 0: Price above threshold
bytes memory payload = abi.encode(
    pythPriceFeedId,   // bytes32 - e.g., ETH/USD feed
    100000_00000000,   // int64 - $100,000 (8 decimals)
    uint64(block.timestamp + 7 days)  // deadline
);

uint256 popId = registry.createPOP(
    pythResolver,
    0,  // Template 0
    payload,
    // ... windows
);

Optimistic Resolver

Human judgment for subjective outcomes. Anyone can propose answers; disputes go through the two-round system.

Templates:

Answer Type: BOOLEAN

// Template 0: Arbitrary question
bytes memory payload = abi.encode(
    "Will the US pass a crypto regulatory framework in 2025?",
    uint64(block.timestamp + 365 days)  // resolution deadline
);

uint256 popId = registry.createPOP(
    optimisticResolver,
    0,  // Template 0
    payload,
    // ... windows
);

Building Custom Resolvers

Implement the IPopResolver interface to create custom resolution logic:

contract MyCustomResolver is IPopResolver {
    // Store POP-specific data
    mapping(uint256 => MyPopData) private _popData;

    function onPopCreated(
        uint256 popId,
        uint32 templateId,
        bytes calldata payload
    ) external override returns (POPState) {
        // Decode and validate payload
        (param1, param2) = abi.decode(payload, (Type1, Type2));
        require(isValidParams(param1, param2), "Invalid");

        // Store for later resolution
        _popData[popId] = MyPopData(param1, param2);

        // Return ACTIVE to auto-approve, PENDING if manual approval needed
        return POPState.ACTIVE;
    }

    function resolvePop(
        uint256 popId,
        address caller,
        bytes calldata payload
    ) external override returns (bytes memory) {
        MyPopData storage data = _popData[popId];

        // Your custom resolution logic
        bool result = _determineOutcome(data, payload);

        // Return ABI-encoded result
        return abi.encode(result);
    }

    function getTemplateAnswerType(uint32)
        external pure override returns (AnswerType) {
        return AnswerType.BOOLEAN;
    }
}

Resolver Design Guidelines

Resolver Use Cases

Use Case Data Source Answer Type
Price predictions Pyth, Chainlink BOOLEAN
Sports outcomes Optimistic (human) BOOLEAN
Election results Optimistic (human) BOOLEAN/GENERIC
Weather data Custom oracle NUMERIC
On-chain state Direct read BOOLEAN/NUMERIC
Random numbers VRF, commit-reveal GENERIC

Need a custom resolver? Check the examples repository for resolver templates, or reach out on Discord for guidance.