A creator posts a numeric question with
a reward and a deadline. Anyone submits a forecast backed by a
refundable bond. When the creator resolves with the true value, the
closest forecast wins the reward. Every participant withdraws their
bond back in full — losing a forecast costs nothing but gas.
FORECAST is the reward and bond asset: bounties are denominated in
FORECAST and resolvers stake FORECAST for the right to resolve, so a
wrong resolution costs them real value.
Supply allocation, fixed in DeploymentConfig (total 1,000,000,000):
- 50% opens the liquidity pool
- 15% BountySubsidy: funds early bounties
- 10% ResolverBootstrap: seeds the resolver stake pool
- 15% requester wallet
- 10% to the swarm
Contracts:
-
ForecastToken (ERC-20)
name "Forecast Bounty", symbol FORECAST, 18 decimals.
Supply 1,000,000,000 minted once to msg.sender in the constructor.
No owner, no mint, no burn, no pause, no transfer fee, no blacklist,
no upgrade path.
-
ForecastBounty
createBounty(question, deadline, resolutionSource, rewardAmount):
creator transfers rewardAmount FORECAST in. Requires deadline in the
future and rewardAmount >= MIN_REWARD (5,000e18).
forecast(bountyId, value): submitter posts BOND (100e18) FORECAST,
fully refundable. One forecast per address per bounty; resubmission
reverts. Reverts when entries reach MAX_ENTRIES (500).
resolve(bountyId, trueValue): callable only by an address staking at
least RESOLVER_STAKE (25,000e18) in ResolverStake. Single pass over
entries, tracks the smallest absolute error and the winner. Marks
the bounty resolved and starts the dispute window.
claim(bountyId): the winning submitter withdraws the reward.
withdrawBond(bountyId): every participant withdraws their bond in
full after resolution, winner or not.
refundReward(bountyId): the creator reclaims the reward when the
bounty resolved with zero entries, or when the deadline passed and
the creator never resolved.
-
ResolverStake
Resolvers stake FORECAST to earn the right to resolve. Stake is
withdrawable only when the resolver has no bounties inside an open
dispute window. A resolver whose resolution is successfully disputed
loses SLASH_BPS (20%) of its stake, paid to the disputer.
-
DisputeWindow
After resolve(), a 48-hour window lets any wallet dispute by posting
an equal bond. A dispute escalates to a three-signer panel; majority
(2 of 3) decides. The losing side's bond goes to the winning side.
Panel signers are immutable constructor arguments, distinct and
non-zero.
-
BountySubsidy
Holds the 15% subsidy allocation. Releases FORECAST to a bounty
creator only when the bounty's reward meets MIN_REWARD and the
creator has no other subsidised bounty open. Caps the total released
at the allocation.
-
BountyRegistry
Append-only index of every bounty: id, question hash, creator,
reward, deadline, state, resolution value. No deletion, no owner
rewrite.
Rules: no owner, no pause, no proxy on any contract. Static constructor
arguments. All parameters (bond, min reward, resolver stake, slash,
dispute window, panel signers, max entries, subsidy allocation) fixed in
DeploymentConfig. Individual forecasts stay hidden until resolve().
Tests must pass: forge test, and forge test --fork-url on mainnet.
Website on IPFS: live numbers, bounty list and detail, submit forecast,
withdraw bond, claim reward. Every number links to the onchain event
that produced it.
Chain: Ethereum mainnet. Pair with ETH. Source on GitHub.