Branching Oracle Base Layer

Draft

Zoltar White Paper

Zoltar is a generalized branching oracle and coordination layer for binary, categorical, and scalar questions. Rather than forcing a single answer when disagreement persists, it represents unresolved outcomes as explicit child universes. After a fork, REP holders may migrate or split their claims across one or more selected branches.

The design closely follows the Colored Coins model: the protocol branches state first, while applications and their users later coordinate which branch ultimately carries economic value.

Zoltar is not itself a prediction market or an outcome-reporting oracle. Instead, it provides the shared infrastructure for questions, REP tokens, and universe forks. Any application can build on top of it and define its own local dispute process. If disagreement cannot be resolved locally, anyone able to commit the required REP threshold may fork an unforked universe using an eligible ended global question. The resulting child universes become the new foundations from which applications may choose to continue.

Lifecycle Timeline

#

Zoltar's lifecycle has six conceptual steps, from question registration through post-fork coordination.

1. Register question

ZoltarQuestionData stores the question and defines its valid answer space.

2. Disagreement persists

After the question end date, any address able to supply the threshold REP can call forkUniverse. Zoltar does not verify that a disagreement exists; applications decide when a fork is justified.

3. Parent universe forks

Zoltar records the fork question and deterministically defines every valid child branch.

4. Child universes deploy lazily

Branches exist by deterministic id first; contracts are deployed only when needed.

5. REP holders split

Migration balances mint child REP into one or more selected branches.

6. Coordination concentrates value

The protocol does not pick a winner. Users and applications decide where durable activity continues.

1. System Overview

#

Zoltar has one job: define the valid universes that higher-level applications can rely on. It does not implement the market, collateral, or underwriting system built on top of it elsewhere in the repo. Its role is narrower and more fundamental:

In practice, that means an application can register a question, trigger a fork after that question ends, and consume the child-universe structure that Zoltar defines. Only Zoltar can mint the child-universe ReputationToken; genesis REP is separately deployed and supplied to Zoltar. Mainnet uses the existing external REP deployment, while Sepolia uses the reviewed deterministic genesis deployment.

Zoltar Contracts

2. Universe Model

#

Security assumptions: A23 verified deployment, A26 Ethereum execution, and A27 cryptographic identity.

A universe is one branch of protocol state. The Zoltar.Universe struct stores the minimum data needed to identify that branch and connect it to its parent:

Universe 0 is the genesis universe. Its network-specific REP token is supplied to the Zoltar constructor. Mainnet uses the existing REP deployment; Sepolia deterministically deploys a genesis REP token from the configured initial-holder allocations before deploying Zoltar. Child universes are identified deterministically as:

childUniverseId = uint248 ( keccak256 ( abi.encode ( parentUniverseId , outcomeIndex ) ) )

Child Universe IdChild universe ids are deterministic hashes of the parent universe and outcome index.

Deterministic child ids make each branch reproducible from parent universe and outcome index alone. Child universes are deployed lazily when a forked branch is actually needed.

Universe Tree

Forking parent Invalid branch Valid outcome branches

Universe treeA fork creates the full valid branch set; no branch is privileged by the contract.

Important distinction Zoltar defines the branch set. It does not select one canonical child universe or delete the others.

Global Question Scope

Questions are global protocol objects in Zoltar. forkUniverse checks that the target universe exists, still has supply, has not already forked, and that the supplied question exists and has ended. It does not require the question to have been created for that universe. Applications that need a stricter universe/question relationship enforce it above Zoltar.

Accepted eligibility boundary Zoltar intentionally accepts any existing ended global question. It does not require a minimum creation age, prior universe registration, or proof that the fork's disruption is smaller than its economic benefit. The fork-threshold REP commitment and configured haircut are the protocol's admission mechanism. A stricter relevance, aging, or cost-benefit rule is not a Zoltar invariant.

3. Fork Thresholds and REP Economics

#

To trigger a Zoltar fork, the caller must commit the forkThreshold: the parent universe's theoretical REP supply divided by the configured threshold divisor, rounded down. The REP threshold and haircut are the intended admission cost for a fork, including unnecessary forks that impose migration work on applications using that universe.

Both the threshold and the haircut are intended to make unnecessary forks economically costly. Forking affects applications and users relying on that parent universe; each application chooses which child branch, if any, to continue using.

Security assumptions: A07 fork value preservation, A08 REP valuation, A05 lineage access value, A21 genesis REP behavior, and A25 safe immutable parameters.

forkThreshold = totalTheoreticalRepSupply forkThresholdDivisor

Fork ThresholdWith the default divisor of 20, this is approximately 5% of theoretical REP supply, subject to integer flooring.

After triggering the fork, the full threshold leaves the parent universe: forkUniverse removes that parent REP and reduces parent theoretical supply by the full threshold. The burn divisor then controls the child-REP minting credit. With forkBurnDivisor = 5, the uncredited haircut is ⌊forkThreshold / 5⌋, approximately 20% of the threshold. The remaining forkThreshold - ⌊forkThreshold / 5⌋ becomes migration credit: equivalently ⌈4 × forkThreshold / 5⌉, approximately 80%.

The constructor rejects forkBurnDivisor < 5. This caps the uncredited haircut at 20%: a larger haircut can leave an own-fork escalation continuation—the child game carrying unresolved deposits after its pool's escalation game triggers the universe fork—with less REP than its maximum winning payout.

uncreditedForkHaircut = forkThreshold forkBurnDivisor

Fork HaircutThe default uncredited share is ⌊forkThreshold / 5⌋, approximately 20% of the threshold deposit and rounded down; the full parent-REP threshold is still removed from the parent universe.

forkInitiatorMigrationBalance = forkThreshold - uncreditedForkHaircut

Initiator Migration BalanceWith the default burn divisor of 5, the initiator receives forkThreshold - ⌊forkThreshold / 5⌋ = ⌈4 × forkThreshold / 5⌉: approximately 80% of the threshold, rounded up when the threshold is not divisible by five.

Implementation entry point

forkUniverse applies the threshold, removes the full parent-REP threshold, reduces parent theoretical supply by that amount, and credits only the post-haircut migration balance to the initiator.

Threshold Deposit Split

Threshold Deposit SplitThe full parent-REP threshold leaves parent supply. Most is re-expressed as migratable child-REP credit; the haircut is not credited.

Genesis REP cannot be burned natively, so the contract transfers it to the configured burn address. Child-universe REP is minted and burned directly by ReputationToken under Zoltar’s control.

A child's theoretical supply is a maximum for REP that can be minted in that branch. It starts from the parent's pre-fork theoretical supply and subtracts only the uncredited haircut. Later REP added to a migration balance converts 1:1; only fork initiation pays this admission cost. A holder can voluntarily remove REP and reduce theoretical supply through Zoltar.burnRep; the child token's burn entrypoint itself is restricted to Zoltar.

Repeated-fork threshold decay

Along one lineage, each fork subtracts its floored haircut from child theoretical supply. With threshold divisor 20 and burn divisor 5, supply is close to 99% of the previous generation, subject to Solidity integer flooring.

Repeated-Fork DecayThe filled curve normalizes genesis theoretical supply to 100%. The dashed curve is the next fork threshold. Integer flooring can shift exact onchain values slightly from this continuous approximation.

Parameter Current value Meaning
genesisReputationToken Constructor parameter Network-specific genesis-universe REP token address. Current values are published in the mainnet and Sepolia deployment manifests; Sepolia derives its value from the deterministic deployment init code and allocation list.
BURN_ADDRESS 0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF Burn sink used for genesis REP
forkBurnDivisor 5 Constructor immutable with a minimum value of 5. The initiator receives the threshold minus ⌊forkThreshold / forkBurnDivisor⌋ as migration credit.
forkThresholdDivisor 20 Constructor immutable. Fork threshold is ⌊totalTheoreticalRepSupply / forkThresholdDivisor⌋; the default deployment value makes it about 5% of supply.

4. Child Universes and REP Splitting

#

Once a universe forks, child universes can be deployed lazily through deployChild. A user can also add more REP into the migration balance with addRepToMigrationBalance. The core post-fork action is splitMigrationRep, which lets a holder mint child-universe REP for valid outcome indices. Supplying no outcome indices is accepted as a no-op at the Zoltar layer.

Security assumptions: A09 truthful-branch value, A11 practical migration, A13 REP liquidity, and A06 lifecycle executors.

For categorical questions, Invalid and any in-range categorical outcome are allowed, while out-of-range values are rejected. For scalar questions, only well-formed scalar encodings are allowed.

The fork question defines the child-branch shape for the whole universe. A child branch may therefore be keyed by Invalid, a categorical outcome index, or a scalar encoding depending on which parent-universe question forkUniverse used for the fork. Downstream applications should treat that branch selector as universe-level metadata rather than assume every child branch is binary.

Implementation entry points

addRepToMigrationBalance prepares additional REP, and splitMigrationRep mints child REP for selected outcomes.

Validation dependency

isMalformedAnswerOption distinguishes valid branches from rejected malformed answers.

Migration Balance Reproduction

Migration Balance ReproductionSelecting multiple branches mints child REP in each selected child universe from the same migration balance.

Colored Coins-style property The same migration balance can mint child REP in each selected child. Later value concentration determines which branch matters economically.

At the implementation level, splitMigrationRep validates each selected outcome against the parent universe's fork question, lazily deploys any missing child universe, and records how much of the caller's migration balance has already been minted into each child. A caller cannot mint more into one child than the source migration balance available to that caller, but the same source balance can be reproduced into multiple valid children.

5. Assumptions and Security Model

#

Zoltar is a Colored Coins-style system, so its security argument depends on user behavior and value concentration rather than on the contract being able to identify one objectively correct branch onchain. This is the security model's EG01 truth-selection exclusion.

Security assumptions: A07 fork value preservation, A09 truthful-branch preference, A03 independent participants, A05 lineage access value, and A15 intended resolvable questions.

A fork only creates branches. If users and future activity concentrate in the branch they regard as truthful, the value of child-universe REP also concentrates there. Holders can reproduce a migration balance into multiple valid child universes, subject to the per-child cap and the gas and coordination costs of doing so. The economic pressure is therefore value concentration: REP in an abandoned branch may keep existing, but it is expected to have little long-term value compared with REP in the branch that markets keep using.

The enforced recursive-fork gas bound and its implementation evidence are maintained in EXT-05.

6. Questions and Outcome Encoding

#

ZoltarQuestionData.QuestionData stores title, description, start and end time, scalar metadata such as numTicks, displayValueMin, displayValueMax, and answerUnit.

Security assumptions: A10 timely outcome evidence, A20 chain-data availability, A27 collision resistance, and A15 question identity and resolvability.

Question ids are deterministic hashes of the question data. For categorical questions, that hash path also includes the sorted categorical outcome options. For scalar questions, there are no categorical labels to include, so the id is determined from the scalar question fields alone.

Every call to createQuestion also requires endTime >= startTime. The contract rejects any question whose end time is earlier than its start time before it reaches scalar or categorical validation.

Categorical Questions

Categorical questions store sorted outcome labels. The implementation requires labels to be non-empty and strictly ordered by hash: each label's keccak256(abi.encode(label)) value must be lower than the previous label's hash, so callers provide labels in descending hash order. The contract stores the labels in outcomeLabels[questionId]. Any number of categorical outcomes can exist at the Zoltar level as long as those conditions hold.

Scalar Questions

Scalar questions store no categorical labels. Instead, numTicks, displayValueMin, displayValueMax, and answerUnit define the answer space. At creation time, scalar questions must satisfy numTicks > 0 and displayValueMax > displayValueMin.

Onchain, each scalar answer is encoded into a single uint256 that packs:

Implementation entry points

createQuestion stores categorical or scalar questions, and ScalarOutcomes formats scalar displays.

Scalar validity rule

Bits 254...240 are reserved and must be zero. Any nonzero reserved bit, or any payout pair whose two 120-bit numerators fail to sum to numTicks, is malformed rather than invalid.

Packed Scalar Answer

Namespace bit First payout Second payout

Packed Scalar AnswerA scalar answer is easier to read as reserved bits, a namespace flag, and two payout fields: bits 254...240 must be zero, 0 in bit 255 is the invalid namespace, and 1 means the payout fields must sum to numTicks.

The all-zero encoding is the canonical Invalid answer for scalar questions. For a valid scalar answer, the two payout numerators must sum exactly to numTicks:

firstPayoutNumerator + secondPayoutNumerator = numTicks

Scalar ValidityA valid scalar answer must allocate all ticks across the two payout numerators.

The all-zero word is the only canonical scalar Invalid value. Any other word with the highest bit clear is malformed, and any word with a nonzero reserved bit in 254...240 is malformed even if the payout fields would otherwise decode cleanly.

At the helper and UI level, a scalar tick index named tickIndex is encoded as:

( numTicks - tickIndex , tickIndex )

Scalar Tick EncodingThe helper encodes a tick as left and right payout numerators.

ScalarOutcomes interprets secondPayoutNumerator as the position along the scalar range:

displayedAtomic = displayValueMin + secondPayoutNumerator ( displayValueMax - displayValueMin ) numTicks

Scalar Display ValueThe contract interpolates the scalar answer with mulDiv, so uneven divisions round down before the value is formatted.

displayValueMin and displayValueMax are stored as 18-decimal fixed-point display bounds. Formatting divides the atomic result by 1e18 and trims trailing zeroes. For example, with displayValueMin = 0, displayValueMax = 10e18, numTicks = 6, and secondPayoutNumerator = 1, the atomic value is ⌊10e18 / 6⌋, which displays as 1.666666666666666666 rather than an unrounded real number.

7. Question Types Supported by Zoltar

#

At the Zoltar layer, market type support comes from how questions and outcomes are encoded in ZoltarQuestionData.

Zoltar can represent arbitrary categorical questions and scalar questions, while higher-level protocols may choose narrower market shapes on top of it. It defines answer spaces and forkable resolution state, not the collateralized trading mechanics that may later be attached to those questions.

8. Invalid vs Malformed

#

Zoltar distinguishes Invalid answers from Malformed answers.

Term Meaning Effect
Invalid A legitimate resolution state. Can be a valid branch and final outcome.
Malformed A submitted outcome index or scalar encoding that does not fit the question’s answer space. Rejected during child-universe REP splitting and fork-aware asset branching.

This distinction matters because malformed answers are rejected, while Invalid remains a valid branch and a valid final outcome.