Docs v2 · testnet

Protocol · TreasuryVault

Every fee is split in thirds — and only the right answers get paid

Markets don't pay a protocol wallet. They push their fees into the TreasuryVault, tagged with the events they settled on. When an event is decided, its fees are split three ways: the resolvers who reported the final outcome, the committee members who voted it (or an insurance reserve), and the treasury.

⅓

Resolvers

Split equally among resolvers whose observation matched the final outcome.

claimResolverReward(eventId)

⅓

Committee or insurance

Disputed: the deciding tier's members who voted the outcome. Undisputed: the insurance reserve.

claimCommitteeReward(eventId)

⅓

Treasury

Protocol treasury (team multisig later), plus rounding dust.

withdrawTreasury(to, amount)

Range-market fee

1%

per trade (tradeFeeBps = 100)

Yes/no market fee

1%

of the losing pool at settlement (feeBps = 100)

Max fee

5%

MAX_FEE_BPS, enforced in each market

Events per deposit

≤16

MAX_EVENTS_PER_DEPOSIT

Fees in, rewards out

1

Market settles

fees accrued

2

depositFees(ids, amt)

tagged per event

3

Event decided

Finalized / Voided / Expired

4

allocate(id)

split into thirds

5

Pull claims

resolvers · committee

  1. 1

    Deposit

    A market calls depositFees(eventIds, amount). The amount is split equally across the IDs. A composite ID is expanded one level into its primitive operands, so a market on “NVDA up AND TSLA down” pays the resolvers of both. Deeper nesting, unknown IDs and rounding go to the treasury.
  2. 2

    Wait for the decision

    Fees sit in pendingFees[eventId] until the event is Finalized, Voided or Expired.
  3. 3

    Allocate

    allocate(eventId) is permissionless (the keeper calls it, and every claim calls it first). It snapshots the final outcome, how many resolvers observed it, and — if there was a dispute — how many members of the deciding tier voted it.
  4. 4

    Claim

    Each resolver or committee member calls the claim function and receives its equal share. The resolver node's rewards duty does this automatically.

The rules, case by case

Event ended…

Finalized, never disputed

Resolver third

correct resolvers

Committee third

→ insurance reserve

Treasury third

treasury

Event ended…

Finalized by a committee

Resolver third

correct resolvers

Committee third

deciding tier's correct voters, + a bonus of up to one more third from insurance

Treasury third

treasury

Event ended…

Finalized, but no resolver observed the final outcome

Resolver third

→ treasury

Committee third

as above

Treasury third

treasury

Event ended…

Voided or Expired

Resolver third

→ treasury

Committee third

→ treasury

Treasury third

treasury (all of it)

Why an insurance reserve?

Disputes are rare, so committee members would rarely be paid if they only earned from the fees of the event they judged — and a disputed event can have thin volume. The committee third of every undisputed event therefore fills an insurance reserve, and each later disputed event draws a bonus of up to one extra third from it. Honest committee work is paid even when the market behind it was small.

Worked example

An NVDA range market with 6 ranges collects 6.00 USDG in trade fees

The market has 5 boundary events, so settlement deposits 1.20 USDG per event. Nobody disputed, and both resolvers reported every boundary correctly. Per event: 0.40 → resolvers (0.20 each), 0.40 → insurance reserve, 0.40 → treasury. Across the market: each resolver earns 1.00 USDG, insurance grows by 2.00, the treasury by 2.00.

The second inflow: dispute bonds

ETH from disputes

The vault is the DisputeManager's treasury. The treasury third of every losing committee bond, and ⅔ of a wrong disputer's bond, is credited to it. sweepDisputeProceeds() pulls that ETH in (the keeper calls it).

Owner controls

The owner (the deployer today; a team multisig later) can spend the treasury and insurance balances — withdrawTreasury, withdrawInsurance, withdrawEth — each emitting an event. The owner can't touch resolver or committee pools.

Function reference

Function

depositFees(bytes32[] ids, uint256 amount)

Who

markets

What

Pull USDG and attribute it to events.

Function

allocate(bytes32 id)

Who

anyone

What

Split a decided event's pending fees into thirds.

Function

claimResolverReward(bytes32 id)

Who

resolvers

What

Collect the resolver share (runs allocate first).

Function

claimCommitteeReward(bytes32 id)

Who

committee members

What

Collect the committee share (runs allocate first).

Function

claimableResolverReward / claimableCommitteeReward(id, who)

Who

view

What

What an address can claim now.

Function

pendingFees(id) · getRewards(id)

Who

view

What

Undivided fees; the per-event snapshot and pools.

Function

treasuryBalance() · insuranceReserve()

Who

view

What

Protocol balances.

Function

sweepDisputeProceeds()

Who

anyone

What

Pull credited dispute ETH from the DisputeManager.

Function

withdrawTreasury · withdrawInsurance · withdrawEth

Who

owner

What

Spend protocol balances.

The vault is protocol infrastructure, not a consumer: it reads the Registry, Composer and DisputeManager to work out who is paid. Markets only push fees into it and still read outcomes through the Event Bus.