Overview
The Task Pool V2 system enables on-chain bounty management: merchants deposit USDC, create tasks with acceptance criteria, solvers claim and complete tasks, verification happens through a pluggable engine, and rewards are distributed with a transparent fee structure. Every Podium organization gets its ownTaskPool + RewardPool contract pair, deployed as Beacon Proxies through the TaskPoolFactory. Global singletons (SolverRegistry, VerificationEngine, IntentRegistryV2) are shared across all tenants.
Settlement Flow
Task Lifecycle
| Status | Description |
|---|---|
Open | Task created, accepting solver claims |
Claimed | A solver has committed to completing the task |
SubmittedForVerification | Solver submitted work, awaiting verification |
Settled | Verification passed, reward distributed |
Cancelled | Merchant or platform cancelled the task (funds refunded) |
Expired | Task deadline passed without completion |
Duration Constraints
- Minimum: 5 minutes
- Maximum: 7 days
Task ID Generation
Task IDs are deterministically computed from the creation parameters:TaskPoolFactory
The factory deploys per-tenantTaskPool + RewardPool pairs using CREATE2 for deterministic addressing.
Creating Tenant Pools
- TaskPool — initialized with references to USDC, VerificationEngine, SolverRegistry, IntentRegistry, and the RewardPool
- RewardPool — initialized with references to USDC, SolverRegistry, IntentRegistry, the TaskPool, and fee configuration
Deterministic Addresses
Pre-compute pool addresses before deployment:Atomic Upgrades
Upgrading the beacon atomically upgrades all tenant pools:TaskPoolImplementation
Per-tenant escrow and task lifecycle contract.Key Functions
| Function | Access | Description |
|---|---|---|
depositFunds(amount) | Any merchant | Transfer USDC in, credit merchant balance |
withdrawFunds(amount) | Merchant | Withdraw from merchant balance |
createTask(merchant, amount, duration, campaignId, method, criteria) | Owner (Podium API) | Create task, register with IntentRegistry |
claimTask(taskId) | Eligible solver | Check SolverRegistry eligibility, record claim |
submitTask(taskId, submissionHash) | Assigned solver | Submit work, route to VerificationEngine |
settleTask(taskId, solver) | VerificationEngine only | Transfer USDC to RewardPool, queue payout |
cancelTask(taskId) | Merchant or owner | Refund escrowed amount to merchant balance |
setPaused(bool) | Owner | Emergency pause: blocks deposits and task creation |
Merchant Balances
Merchants deposit USDC before creating tasks. Task creation debits the merchant’s balance (escrow). Cancellation credits the balance back. This prevents tasks from being created without sufficient funds.RewardPoolImplementation
Per-tenant reward distribution with a three-way fee split.Fee Structure
| Fee | Default | Recipient | Purpose |
|---|---|---|---|
| Protocol fee | 1% (100 bps) | Platform fee recipient | Platform revenue |
| Solver fee | 0.1% (10 bps) | SolverRegistry | Reputation accrual |
| Net payout | 98.9% | Solver | Solver compensation |
setFees).
Payout Flow
WhenTaskPool.settleTask() is called:
- USDC is transferred from TaskPool to RewardPool
queuePayout(taskId, solver, grossAmount)computes the fee split- Protocol fee is credited to the fee recipient’s pending balance
- Solver fee is sent to SolverRegistry via
accrueReward()(updates reputation) - Net payout is credited to the solver’s pending balance
claimRewards() to withdraw their accumulated payouts.
Key Functions
| Function | Access | Description |
|---|---|---|
queuePayout(taskId, solver, grossAmount) | TaskPool only | Compute fee split, queue pending payout |
claimRewards() | Solver or fee recipient | Withdraw all pending payouts |
setFees(protocolFeeBps, solverFeeBps) | Owner | Update fee structure (capped at 10% combined) |
setProtocolFeeRecipient(address) | Owner | Update fee recipient address |
SolverRegistry
Global singleton tracking solver identity, eligibility, and reputation.Solver Profile
Reputation System
- Starts at 5000 on registration
- +10 per completed task (via
accrueReward) - Capped at 9900 (cannot reach 10000)
- No decay mechanism currently — reputation only increases
Key Functions
| Function | Access | Description |
|---|---|---|
register(metadata) | Self-registration | Create profile with reputation 5000 |
isEligible(solver, taskId) | View | Active, registered, and not banned |
accrueReward(solver, amount) | Authorized RewardPools | Increment completed tasks, rewards, reputation |
recordClaim(solver) | Any caller | Increment claim count |
banSolver(solver) | Owner | Permanently ban and deactivate |
deactivateSolver(solver) | Owner | Deactivate without banning |
VerificationEngine
Global singleton routing task completion verification through pluggable strategies.Verification Methods
| Method | Description |
|---|---|
Consensus | Multiple parties agree on task completion |
Oracle | Authorized oracle evaluates and resolves |
AIEval | AI oracle evaluates submission against acceptance criteria |
resolveVerification(taskId, approved) callback. The method enum is recorded for provenance but doesn’t change the on-chain resolution flow — the intelligence is off-chain in the Podium API backend.
Flow
- TaskPool calls
requestVerification(taskId, solver, submissionHash, criteria, method) - Off-chain oracle (the Podium API) evaluates the submission
- Oracle calls
resolveVerification(taskId, approved) - If approved, VerificationEngine calls
TaskPool.settleTask(taskId, solver) - If rejected, the task remains claimable or can be cancelled
Key Functions
| Function | Access | Description |
|---|---|---|
requestVerification(taskId, solver, hash, criteria, method) | Authorized TaskPools | Create pending verification request |
resolveVerification(taskId, approved) | AI oracle or authorized oracles | Resolve request, trigger settlement if approved |
addOracle(address) / removeOracle(address) | Owner | Manage authorized oracle addresses |
authorizeTaskPool(address) / revokeTaskPool(address) | Owner | Manage which TaskPools can request verification |
IntentRegistryV2
Global singleton tracking all intents across tenants for observability and analytics.Key Differences from V1
- UUPS upgradeable (V1 was non-upgradeable)
- Multiple authorized callers instead of single
originSettler - Custom errors instead of require strings
- EIP-7201 namespaced storage
Functions
| Function | Access | Description |
|---|---|---|
registerIntent(intentId, merchant, recipient, amount) | Authorized callers | Record a new intent |
markFulfilled(intentId, solver) | Authorized callers | Mark intent as fulfilled |
addAuthorizedCaller(address) | Owner | Whitelist a new caller (e.g., new TaskPool) |
getAllIntents(offset, limit) | View | Paginated intent listing |
getMerchantIntents(merchant) | View | Intents by merchant address |

