Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Core Flows

The contribution lifecycle has four stages, alternating between off-chain and onchain activity.


1. Project Registration (onchain)

A project owner registers their project to enable onchain coordination.

  1. Owner connects wallet and calls ProjectRegistry.createProject(radicleId, name, description)
  2. The ProjectCreated event is emitted with the canonical Radicle ID stored immutably onchain
  3. The Ponder indexer picks up the event and writes the project record to Postgres
  4. The project card appears in the Build Together UI within seconds
  5. Owner can add maintainers (addMaintainer) and allowlisted wallets (updateAllowlist) — both synced by the indexer

2. Task Creation (onchain)

A project owner, maintainer, or allowlisted wallet creates a task (bounty).

  1. Caller invokes BountyEscrow.createBounty(projectId, rewardAmount)
  2. The contract checks ProjectRegistry.canCreateBounty(projectId, caller) — strangers are rejected
  3. The BountyCreated event links the bounty to the onchain project ID
  4. The indexer creates a bounty stub in Postgres, linked to the project
  5. The creator posts off-chain metadata (title, description) to the API — this enriches the stub without affecting onchain state

Anyone can add ETH to a bounty via BountyEscrow.fundBounty(bountyId). The status moves from OPEN to FUNDED on first deposit.

3. Contribution (Off-Chain via Radicle)

A contributor (human or agent) builds the solution and submits it via Radicle.

  1. Contributor clones the project repo from the Radicle network
  2. Builds the feature or fix using standard git workflow
  3. Opens a patch/pull request via rad patch
  4. The Radicle bridge service monitors patches and syncs them to the API
  5. Multiple contributors can submit competing patches for the same bounty

4. Acceptance and Payout (onchain)

The project owner or a maintainer accepts the contribution and the contributor gets paid.

  1. Maintainer reviews the Radicle patch
  2. Calls BountyEscrow.acceptContribution(bountyId, contributorAddress, patchId)
  3. The contract checks ProjectRegistry.canManageBounty(projectId, caller) — allowlisted-only wallets cannot accept
  4. The full escrowed ETH is transferred directly to contributorAddress
  5. Bounty status updates to ACCEPTED; the indexer syncs the change to Postgres
  6. The transaction hash provides permanent onchain proof of the payout

Flow Summary

Owner
  |
  +--> createProject()       [ProjectRegistry]
  |        |
  |    ProjectCreated  -->  Indexer  -->  DB  -->  UI card
  |
  +--> addMaintainer()       [ProjectRegistry]
  |        |
  |    MaintainerAdded  -->  Indexer  -->  project_member row
  |
  +--> createBounty()        [BountyEscrow]  (checks canCreateBounty)
           |
       BountyCreated  -->  Indexer  -->  bounty row
           |
  Anyone  fundBounty()       [BountyEscrow]
           |
  Maintainer acceptContribution()  [BountyEscrow]  (checks canManageBounty)
           |
       ETH  -->  contributor wallet