Prediction markets need two oracle patterns: (1) on-chain price data for liquid assets and (2) verifiable decisions from off-chain APIs for bespoke events.
Records each market’s oracle config: type, sourceId, timeout, quorumRules.
Single entry that markets call. Delegates to handlers and emits canonical resolution events.
Thin wrapper around Data Feeds. Validates heartbeat/staleness before returning standardized price.
Triggers Functions requests on schedule or at market end, preventing manual intervention.
1) Market registers: type=price_feed, sourceId=Aggregator
address, heartbeat, deviation.
2) Settlement call → OracleRouter → Handler: validates roundId freshness and writes resolved price.
3) Emits MarketResolved(marketId, price, roundId, updatedAt).
1) Market registers sourceId with subscriptionId, router,
and expectedSchema.
2) Automation upkeep triggers at market end → calls Functions with specific question payload.
3) Functions JS executes HTTP call, normalizes to JSON, and returns verified status.
4) OracleRouter receives callback, validates signature/replay guard, and finalizes settlement.
interface IOracleRouter {
function resolvePrice(uint256 marketId) external;
function requestDecision(uint256 marketId) external;
event MarketResolved(uint256 indexed marketId, bytes32 resolutionType, bytes data);
}
// Logic: Store feed decimals and convert to 18d fixed-point on read.
// Security: pendingRequestId[marketId] to prevent duplicate callbacks.
const res = await Functions.makeHttpRequest({ url, method: "GET", params });
const { outcome, evidenceUrl, signature } = normalize(res.data);
return Functions.encodeString(JSON.stringify({ outcome, evidenceUrl, signature }));
OracleRouter address to the Proxy's "Consumers" list.nostra-contracts/packages/contracts/reference/feeds.<chain>.json
and surface through the SDK; expose the active feed/updatedAt in nostra-server/api
and show it in the web market details.Detailed steps for using Chainlink price feeds in the Nostra stack:
feeds.<chain>.json under nostra-contracts/packages/contracts/reference/ and mirror keys in .env for deploy scripts (e.g., CHAINLINK_BTCUSD=0x...).OracleRouter (or resolution contract) in the feed’s Consumers/Access UI. Keep that address noted in deployments.json and nostra-server/docs/ops/chainlink.md.resolvePrice calls and monitoring bots.PriceFeedHandler store feed decimals/heartbeat, validate freshness/deviation, convert to 18d, and emit MarketResolved with roundId/updatedAt.Date: December 12, 2025
Error Message: Failed to claim: execution reverted: "Not resolved"
The error occurs in ConditionalTokens.sol:160
The redeemPositions function checks if the condition has been resolved on-chain before allowing
token redemption.
The committed code (HEAD) uses the correct function adminFinalizeResolution().
The uncommitted changes introduced a broken function call resolveMarket() which
does NOT exist in the contract ABI.
| Version | Function Called | Status |
|---|---|---|
| Committed (HEAD) | adminFinalizeResolution(questionId, outcomeSlotCount, payouts) |
CORRECT |
| Uncommitted (working) | resolveMarket(questionId, payoutIndex) |
BROKEN |
resolveMarket() does NOT exist in the ResolutionOracle contract ABIRESOLVEDcondition.isResolved remains falseredeemPositions() reverts with "Not resolved"| Function | Parameters | Access | Description |
|---|---|---|---|
proposeResolution |
questionId, outcomeSlotCount, payouts[] | onlyResolver | Proposes resolution, starts dispute period |
finalizeResolution |
questionId, outcomeSlotCount | onlyResolver | Finalizes after dispute period (1 day) |
adminFinalizeResolution |
questionId, outcomeSlotCount, payouts[] | onlyOwner | Immediate resolution - bypasses dispute period (CORRECT FUNCTION) |
resolveMarket |
- | - | DOES NOT EXIST |
If the uncommitted changes to admin.ts are not needed, simply restore the committed version:
This will restore the working adminFinalizeResolution() calls.
If the uncommitted changes contain other necessary modifications, replace the broken
resolveMarket() calls:
The adminFinalizeResolution function requires a payouts array, not just an index:
| Winning Outcome | payoutIndex | payouts Array |
|---|---|---|
| YES (first outcome) | 0 | [100, 0] |
| NO (second outcome) | 1 | [0, 100] |
The values represent percentage (100 = full payout to that outcome, 0 = no payout).
Any markets resolved while running the uncommitted code are in an inconsistent state:
To fix these markets:
status: 'RESOLVED' in the databaseadminFinalizeResolution manually or via a migration scriptconditionalTokens.conditions(conditionId).isResolved| Aspect | Details |
|---|---|
| Root Cause | Uncommitted changes introduced broken resolveMarket() call |
| Committed Code | Correct - uses adminFinalizeResolution() |
| Fix | Discard changes or fix resolveMarket → adminFinalizeResolution |
| Restart Required | Yes - API server restart needed after fix |