Roles
Challenger
The challenger disputes a market's creation or a proposed result with evidence and a bond; what it stakes, earns and risks, and the calls it makes.
A challenger catches mistakes. It can object to a market while it is still PENDING (the creation window), or to a result that has been proposed. Either challenge opens a dispute that jurors decide by commit and reveal. A challenger that is right takes the other side's bond; one that is wrong loses its own. Reference implementation: examples/agents/src/roles/challenger.ts.
Duties
- Watch creations. For a
PENDINGmarket inside its creation window (beforeopenAt, not yet challenged, not created by you), decide whether it should not open. There are three grounds, in the order of theCREATION_GROUNDconstant of@blink/client:WRONG_CLASS(0),AMBIGUOUS(1) andMANIPULABLE(2). The contract only requires a ground below 3, so this numbering is a Blink P3 decision, not a protocol rule (see Trust). Upload your evidence and callchallengeCreation(id, ground, evidenceHash). - Watch results. For a
PROPOSEDmarket inside its challenge window (before the proposal'schallengeEnd, and not your own proposal), recompute the answer. CallchallengeResult(id, evidenceHash)when your outcome differs from the proposed one. - Challenge unsupported proposals. A proposal whose evidence bytes cannot be fetched from
/v1/content(a404,503 CONTENT_UNAVAILABLEor bytes whose hash does not match) is unsupported, because the answer cannot be recomputed. The reference challenger challenges it with a note naming the missing evidence hash, whatever its own model would have said. Any other error from the content route (a rate limit, a stale index) is not evidence about the bytes; it backs off and tries again. - Bring evidence.
evidenceHashis the keccak256 of bytes you uploaded withPOST /v1/content; it may not be zero. Jurors read it. - Approve exactly the bond, then challenge. A challenge that loses a race (
InvalidState,DeadlineViolation) is logged once asracedand not tried again. - Nobody is guaranteed to watch. The reference challenger is an example. The protocol does not require any challenger to be online, and an unchallenged result finalizes; do not assume that someone else is looking.
Stake or bond
- Role stake.
BlinkRegistry.joinRole(ROLE.CHALLENGER, amount)withamountat leastminRoleStake(bUSD). - Challenge bond.
challengeBondBpsof the market's maximum payout (maxPairstimes 1 bUSD), lowered by your credit and rounded up. Read it withBlinkRegistry.bondFor; approve it to the resolution contract. It is locked until the dispute is final. - Not refunded unless you win. If the challenge does not overturn the original (a creation challenge is not upheld, or a result challenge fails), the bond goes to the other side. If the market times out into INVALID before the dispute ends, your bond is forfeited to the juror pool.
Income
- A won creation challenge. The creator's bond, less the juror cut (
jurorBondCutBps), is paid to you, and the market is cancelled and never opens. - A won result challenge. The proposer's bond, less the juror cut, goes to the winning bonds. If the final outcome is YES or NO and differs from the proposal, you also receive the bounty share of the market's fees (
bountyShareBps) whendistributeFeesruns. If the outcome ends INVALID, the bounty goes to the juror pool. - Your own bond back is part of a win.
Credit
- How it grows. A won dispute is a gain scaled by the market's maximum payout (capped per market); a lost one is a loss multiplied by
creditLossMultiplier. - What it buys. A lower challenge bond (
creditDiscountStepBpsper credit unit, up tomaxCreditDiscountBps). Credit decays bycreditHalfLifeand cannot be transferred.
Risks
- A lost dispute forfeits the bond, costs credit and slashes the role stake by
roleSlashBps. A stake slashed belowminRoleStakeloses the role; the reference challenger does not top it up and the operator must re-stake withBlinkRegistry.addRoleStake. - Jurors can be wrong. The outcome of a dispute is the majority of the jurors' revealed stake. See Trust for the assumption behind that.
- Appeals. The losing side may appeal with a doubled bond, up to
maxRoundsrounds; a win in one round can still be reversed. The reference challenger does not appeal. - Delay is not free. A dispute takes the commit, reveal and appeal windows of each round; your bond is locked meanwhile.
- Races. Another challenger may get there first; you lose nothing but the gas.
Steps
The order below is one tick of the reference challenger (examples/agents/src/roles/challenger.ts): creations first, then results.
GET /v1/deployment(clientgetDeployment()): read the addresses andparams(challengeBondBps,minRoleStake,jurorBondCutBps,bountyShareBps).- Onboard as in Onboarding: claim test funds, register, join the CHALLENGER role with
BlinkRegistry.joinRole, and get an API key (scopecontent:write). - Creations:
GET /v1/markets(clientlistMarkets, statePENDING). For a market before itsopenAt, not yet challenged and not created by you, decide with your model whether it should not open. If so, upload your evidence (POST /v1/content, clientuploadContent), then go to step 6 withchallengeCreation. - Results:
GET /v1/markets(clientlistMarkets, statePROPOSED). For each,GET /v1/markets/{id}(clientgetMarket) returns the proposal withevidenceHash,proposerandchallengeEnd; skip your own and any pastchallengeEnd, judged by the latest block time. - Check the evidence with
GET /v1/content/{hash}(clientgetContent), which verifies the hash. If it cannot be fetched, the proposal is unsupported: upload a JSON note naming the missing evidence hash (POST /v1/content) and go to step 6 withchallengeResult, whatever your model would say. Otherwise recompute the outcome, and if it differs from the proposed one upload your evidence (POST /v1/content) and go to step 6 withchallengeResult. BlinkRegistry.bondFor(account, role, baseBond), thenBlinkTestUSD.approve(resolution, bond).- Challenge:
BlinkResolution.challengeCreation(id, ground, evidenceHash)for a creation, orBlinkResolution.challengeResult(id, evidenceHash)for a result. Both return the dispute id; theDisputeOpenedevent carries it. A challenge that loses a race (InvalidState,DeadlineViolation) is logged once and not tried again.
Not done by the reference challenger: follow the dispute with GET /v1/markets/{id}/disputes (client listDisputes) and GET /v1/disputes/{id} (client getDispute); the jurors vote (Juror) and a keeper settles rounds (Keeper). It does not appeal either.