Roles
Proposer
The proposer submits a market's result with archived evidence and a bond after it closes; what it stakes, earns and risks, and the calls it makes.
A proposer reports the result of a market after it closes. It archives the evidence, posts a bond and calls propose with the outcome. If nobody challenges the proposal inside the challenge window, anyone can finalize it and the proposer gets its bond back plus a share of the market's fees. If someone challenges, jurors decide and the loser's bond is slashed. Reference implementation: examples/agents/src/roles/proposer.ts.
Duties
- Wait for the window. A proposal is possible only for an
OPENmarket, fromcloseAtuntilproposalDeadline, and only once per market (InvalidStateafter another proposal). If nobody proposes, the market times out to INVALID at its hard deadline. - Decide the outcome yourself.
YESorNO; a proposal cannot be INVALID. For a class A market the answer is the template's program run over the archived source bytes (gmLtV1OutcomeforGM_LT_V1), so anyone can recompute it. For class B and C it is your own judgment of public documents. - Archive the evidence first. Upload the evidence bytes with
POST /v1/content; the content store names them by their keccak256, which is theevidenceHash. PassevidenceURIas/v1/content/<hash>. Platform storage is a convenience: anyone can mirror the bytes by hash, and you should. - Evidence you cannot serve is a lost proposal. A proposal whose evidence bytes cannot be fetched from
/v1/content(a404,503 CONTENT_UNAVAILABLEor bytes whose hash does not match) is unsupported. Jurors vote against it and challengers challenge it. Never propose bytes you did not archive. - Approve exactly the bond to the resolution contract, then call
propose. If another proposer wins the race, the call reverts withInvalidState; the reference proposer logsracedonce and never proposes on that market again. - Appeal a lost round, once. When a round of a dispute over your proposal settles against it and your model says the proposal still stands, call
appealwith a bond twice the last one, before the round's appeal window ends and while the new round can still finish before the hard deadline. Appeals stop atmaxRounds. The reference proposer appeals each dispute at most once.
Stake or bond
- Role stake.
BlinkRegistry.joinRole(ROLE.PROPOSER, amount)withamountat leastminRoleStake(bUSD). - Submission bond.
proposerBondBpsof the market's maximum payout (maxPairstimes 1 bUSD), lowered by your credit and rounded up. Read it withBlinkRegistry.bondFor, never compute your own. It is locked until the proposal finalizes unchallenged, or the dispute ends. - Appeal bond. Twice the previous bond in the dispute, again in bUSD.
Income
- Resolution share. When the market is
FINALand the final outcome is the one you proposed,distributeFeespays youresolutionShareBpsof the fee pool, less the keeper's tip (keeperTipBps). If the outcome differs or is INVALID, that share goes to the juror pool. - A won dispute. If a challenge fails, the challenger's bond, less the juror cut (
jurorBondCutBps), is split among the winning side's bonds. - Bond back. An unchallenged proposal gets its bond back when
finalizeUnchallengedruns.
Credit
- How it grows. A proposal that survives the window or wins its dispute is a gain, scaled by the market's maximum payout and capped per market. A lost dispute is a loss multiplied by
creditLossMultiplier. - What it buys. A lower bond (
creditDiscountStepBpsper credit unit, up tomaxCreditDiscountBps) and a shorter challenge window: each credit unit takeschallengeWindowStepSecondsoffresultChallengeWindow, but never belowminResultChallengeWindow. Credit decays bycreditHalfLifeand cannot be transferred.
Risks
- Losing a dispute forfeits the bond to the winning side, costs credit and slashes the role stake by
roleSlashBps. A stake slashed belowminRoleStakeloses the role (hasRoleturns false and the next transaction revertsMissingRole). The reference proposer does not top it up; the operator must re-stake withBlinkRegistry.addRoleStake. - Missing evidence. See Duties: an unsupported proposal loses. Keep the bytes available for the whole challenge and dispute time.
- Do not rely on being unchallenged. A challenger who overturns a proposal earns the bounty share of the fees (
bountyShareBps) as well as the loser's bond, so catching a wrong result pays. No challenger is guaranteed to be online, and an unchallenged result finalizes; a wrong proposal is a bet that nobody is watching, and it puts the bond at risk if anyone is. - Locked funds. The bond and the role are locked until the market is final, which can take until the hard deadline.
- Deadlines. A late proposal reverts (
DeadlineViolation). The reference proposer reads chain time, not its own clock. - Source documents are untrusted. Class A uses a deterministic parser on the archived bytes so that text inside a source cannot steer the answer.
Steps
The order below is one tick of the reference proposer (examples/agents/src/roles/proposer.ts): appeals first, then new proposals.
GET /v1/deployment(clientgetDeployment()): read the addresses andparams(proposerBondBps,minRoleStake,maxRounds, the challenge windows).- Onboard as in Onboarding: claim test funds, register, join the PROPOSER role with
BlinkRegistry.joinRole, and get an API key (scopecontent:write). - Appeal a lost round, for each market you proposed on:
GET /v1/markets(clientlistMarkets, stateDISPUTED),GET /v1/markets/{id}(clientgetMarket) to confirm you are the proposer,GET /v1/markets/{id}/disputes(clientlistDisputes) andBlinkResolution.getDispute(disputeId)for the settled round. Reconcile this wallet’sAppealedevents and any saved appeal intent before sending another appeal. If it went against your proposal and the appeal window and the hard deadline allow it:BlinkTestUSD.approve(resolution, bond)with twicelastBond, thenBlinkResolution.appeal(disputeId). - Find markets to propose on:
GET /v1/markets(clientlistMarkets, stateOPEN): markets whosecloseAthas passed and whoseproposalDeadlinehas not, judged by the latest block time, that you have not proposed on. - Work out the outcome (
YESorNO) from the spec and the sources, and archive the evidence bytes:POST /v1/content(clientuploadContent). BlinkRegistry.bondFor(account, role, baseBond), thenBlinkTestUSD.approve(resolution, bond).BlinkResolution.propose(id, o, evidenceHash, evidenceURI). TheProposedevent carrieschallengeEnd. AnInvalidStateanswer means another proposer was first.
Not done by the reference proposer, and left to a keeper or the operator: BlinkResolution.finalizeUnchallenged(id) after the window (anyone may call it; your bond is returned), and BlinkMarkets.distributeFees(id) after the market is final, which pays your share.