Boost a Bounty: Feature Guide - zeroauthority-dao/mission GitHub Wiki
As of 2026-10-14.
The boost-bounty branch adds three ways to reward people on Stacks bounties: boosting a bounty's prize, tipping a submission, and paying participants who didn't win. A new boost-pool contract handles the first and third; BoostX handles the second. The existing bounty contracts are unchanged, so bounties already live can be boosted.
| Feature | Who uses it | Where the money goes | When | Networks |
|---|---|---|---|---|
| Boost a bounty | Anyone, including the creator | Held in boost-pool, paid to the winners |
While the bounty is open or paused | Testnet now; mainnet after review |
| Boost a submission | Anyone except the submitter | Straight to the submitter's wallet via BoostX | Any bounty status, including closed | Mainnet only |
| Reward Options | The bounty creator only | From the creator's wallet to chosen non-winners | After winners are selected | Testnet now; mainnet after review |
Bounty boosts and Reward Options are behind the NEXT_PUBLIC_BOOST_POOL_ENABLED flag, which defaults to off. Submission boosts need no flag: they show on mainnet only. Notifications, badges and a boost history show the results on the bounty pages.
Anyone can add STX, a whitelisted SIP-010 token or an NFT to an open bounty's prize. The boost is held in boost-pool and paid to the winners; if the bounty is cancelled or expires, each booster takes back exactly what they put in. boost-pool charges no fee.
How it works for users
- A rocket button shows on the bounty page and bounty cards while the bounty is open and on Stacks.
- The booster picks an asset and amount, adds an optional message (up to 256 characters) and signs. Mixing assets, say STX plus an NFT, takes one signature per asset.
- The prize line updates once the transaction confirms, for example "500 STX + 120 STX boosted", and the creator gets a notification.
- When the creator selects winners, each winner gets a "rewards claimable" notification and a Claim boosted rewards button. The first claim also finalizes the pool, which locks in the winners and totals.
- If the bounty is cancelled, or no winner is picked within 12,960 Bitcoin blocks (about 90 days) of the first boost, boosters see Refund my boost.
How the prize is split
| Bounty type | Who gets the boost |
|---|---|
| Single winner | The winner, 100% |
| NFT bounty | The winner, 100% |
| Multi-winner and verified | Split equally across the winners |
| Custom split | In proportion to the bounty's own split |
Rounding leftovers and any boosted NFT go to the first winner. Each winner pulls their own share, so one failed transfer never blocks the others.
Rules the contract enforces
- Boosts are rejected once the bounty is closed, cancelled or unknown.
- Tokens must be enabled in
ZADAO-token-whitelist-v1. - A bounty's type is locked by its first boost.
- Refunds stop once the pool is finalized. Finalizing after some refunds pays out only what's left.
- The contract owner can't move pooled funds.
A submission boost is a direct tip to the person who made the submission, sent through BoostX (boostx-v2). It works at any bounty status, including after the bounty closes, and only on mainnet because BoostX isn't deployed elsewhere.
How it works for users
- A rocket shows on each confirmed submission, on the bounty page and the review page. It's hidden from the submitter, since BoostX rejects self-boosts.
- The booster picks STX, a whitelisted token or an owned NFT, and an optional message.
- The modal shows BoostX's fee and what the submitter receives before signing.
- The submitter gets a notification, and the submission shows a Boosted badge with its tip totals.
Fees (read from BoostX at signing time, currently 0.1 STX per asset)
| Asset | Submitter receives | Fee |
|---|---|---|
| STX | Amount minus the fee; the amount must be larger than the fee | Taken from the amount |
| SIP-010 token | The full amount; the wallet must hold more than the amount | Separate STX payment |
| NFT | The NFT | Separate STX payment |
Every boost uses BoostX's shared options contract, so boosters don't deploy anything. Each tip links back to the submission's page on ZADAO, so it also counts on boostx.cc.
After selecting winners, the bounty creator can pay non-winning participants from their own wallet, in STX or a whitelisted token. The three options differ only in who gets paid; each recipient gets the same amount.
| Option | Creator enters | Who gets paid |
|---|---|---|
| Reward all equally | Amount each, token | Every non-winner with a confirmed submission |
| Reward selected | Amount each, token, then ticks people | The ticked non-winners |
| Reward random | Amount each, token, how many | That many non-winners drawn by NovaBotAI |
How it works for the creator
- After winner selection, the review page opens the Reward participants screen. Until the selection confirms on chain, it says so and offers Check again.
- The screen shows the total (amount each × recipients), the creator's balance, and how many signatures are needed.
- Recipients are paid in batches of up to 100, one signature per batch. A failed batch can be signed again.
- Skip for now closes the screen; a Reward participants button on the bounty reopens it, with any unpaid rounds listed first.
- Each recipient gets a notification and a Participation reward badge once their batch confirms.
How the random draw works and how to check it
- The seed is the latest Stacks block hash plus the bounty id, so no one can pick it in advance.
- The draw shuffles the eligible list, sorted by submission id, using SHA-256 of the seed, and takes the first N.
- The seed, the eligible list and the picks are saved with the round and the seed is shown as "Picked by NovaBotAI". Anyone can re-run the draw and get the same picks.
- A draw can't be redrawn: the creator pays exactly those picks.
Rules the contract enforces
- Only the bounty creator can pay, and only after winners are selected.
- Every recipient must have a submission and must not be a winner. For verified bounties, which have no submission lookup, the server checks participation instead.
- No one is paid twice in the same round.
A bell in the header, shown when a wallet is connected, lists bounty notifications with an unread count. Opening it marks them seen, and each one links to the bounty or submission. Notifications are created only when the transaction confirms; failed transactions create none.
| Notification | Who gets it | Sent when |
|---|---|---|
| Bounty boosted | The bounty creator | A prize boost confirms |
| Submission boosted | The submitter | A tip confirms, once per boost even if it used several assets |
| Rewards claimable | Each winner | Winners are selected on a bounty with boosts |
| Refund available | Each booster | The bounty is cancelled or the boost expires; checked every 6 hours |
| Participation reward | Each paid participant | Their reward batch confirms |
On the bounty pages
- Prize line: the base prize plus boosts, for example "500 STX + 120 STX boosted · 1 NFT", and "Boosted by N supporters".
- Boosted badge on bounty cards and on tipped submissions, with the tip totals.
- Participation reward badge on paid non-winners.
- Boost history: who boosted, prize or tip, asset, message and a link to the transaction.
Only confirmed transactions count toward any of these totals.
Every boost, claim, refund and reward follows the same path: the wallet signs, the server checks the signed transaction, broadcasts it and records it as pending, and the transaction poller confirms it and creates notifications. The user pays the network fee; nothing is sponsored.
flowchart LR
W["Wallet signs<br/>user pays the fee<br/>caps on what leaves"] --> S["Server checks<br/>contract, sender,<br/>bounty, amounts"]
S -->|a wrong tx is refused<br/>and never sent| B["Broadcast<br/>saved in the database<br/>as pending"]
B --> P["Poller confirms<br/>status updated and<br/>notifications sent"]
B -->|sends tx| C["Stacks chain<br/>boost-pool reads the bounty contracts<br/>BoostX pays submitters directly"]
C -->|result| P
The server check is the gate: a transaction that doesn't match what the user asked for is never broadcast.
Server checks before broadcasting. Each transaction type has an inspector that refuses a transaction unless it calls the right contract and function, comes from the right wallet, targets the right bounty, and uses deny-mode post-conditions that cap exactly what leaves the wallet. A reward batch must match the stored round's recipients and amount, in order.
Contract. boost-pool reads each bounty's status and winners from the existing bounty contracts through one adapter per bounty type, so those contracts didn't change. It holds prize boosts, pays claims and refunds, and moves participant rewards straight from the creator to each recipient without holding them.
| Part | Where |
|---|---|
| Pool contract and tests |
packages/contracts/contracts/boost-pool.clar, tests/boost-pool.test.ts
|
| Transaction inspectors |
packages/web/src/lib/boost/inspect-pool-tx.ts, inspect-boostx-tx.ts, lib/bounty/participant-rewards/inspect-reward-tx.ts
|
| Server actions |
packages/web/src/actions/bounty-actions/ (record-pool-boost, record-submission-boost, record-boost-payout, participant-rewards, bounty-notifications) |
| Random draw | packages/web/src/lib/bounty/participant-rewards/random-pick.ts |
| Confirmations and notifications |
packages/web/src/lib/boost/on-tx-settled.ts, called from toad/check-tx-status.ts
|
| UI |
packages/web/src/components/bounty/boost/, components/bounty/reward-participants/, components/layout/bounty-notifications-bell.tsx
|
| Database |
BountyBoost, BountyBoostPayout, BountyNotification, BountyRewardRound, BountyRewardRecipient; migration 20261012120000_bounty_boosts
|
Testnet is deployed: all seven contracts are live at ST1APRYRM9EV1KR73X2TRZCE8FZGFEF0YP3J1MNE1. Mainnet needs only boost-pool, deployed by the bounty deployer SP2GW18TVQR75W1VT53HYGBRGKFRV5BFYNAF5SS5J, after the security review.
| Network | Contracts | Status |
|---|---|---|
| Testnet | Token whitelist, five bounty contracts, boost-pool (plus two trait contracts) |
Deployed |
| Mainnet |
boost-pool only; the bounty contracts are already live |
Waiting on security review and token check |
Deploys use Clarinet plans from packages/contracts: npm run deploy:<network>:plan, review the plan, then npm run deploy:<network>:apply. A check script refuses any plan sent from the wrong address, publishing the wrong contracts, or built from stale source. The deployer's seed phrase stays in a gitignored settings file.
To turn it on for a site (testnet or mainnet)
- Apply the database migration with
prisma migrate deploy - Set
NEXT_PUBLIC_BOOST_POOL_ENABLED=trueand rebuild the web app - Restart the transaction poller:
pnpm --filter @repo/zero-authority start-tx-checker
Limits
- Stacks bounties only; Base bounties, Ordinals and a boost leaderboard are out of scope.
- On testnet only STX works for boosts and rewards until the test tokens are redeployed at
STQ5M2WJFPCKFMT63WRQ2T8JNQX70EVKZEPFZS1Pand enabled on the whitelist. - Submission boosts can't be tested on testnet, because BoostX is mainnet only.
- A token whose transfer checks the calling contract will fail inside
boost-pooland BoostX; each listed token needs checking before mainnet. - A new bounty contract type needs a new
boost-poolversion, since the five bounty contract addresses are fixed in it.
Open items
- Testnet end-to-end run: boost, claim, refund, all three Reward Options, notifications
- Security review of
boost-pool - Check every whitelisted token works inside
boost-pooland BoostX - Deploy
boost-poolto mainnet and run the BoostX smoke test
Related docs
| Doc | What it covers |
|---|---|
packages/contracts/docs/contracts-deploy.md |
Step-by-step deploy runbook for testnet and mainnet |
packages/contracts/docs/boost-pool-adapters.md |
How each bounty contract is read, and the mainnet source comparison |
| Clarinet CLI reference | The deployments generate and apply commands used to deploy |
| BoostX | The tipping service used for submission boosts |