Data Marketplace
Data Labeling Marketplace
The Data Labeling Marketplace on PandaChain connects data requesters with workers who label data for ML training. Budgets are held in escrow, payments are automatic, and reputation is tracked on-chain.
How It Works
| Role | Action | Outcome |
|---|---|---|
| Requester | Posts labeling request with budget | Budget locked in escrow |
| Worker | Claims task, submits labels | Earns PANDA per accepted label |
| Requester | Reviews submissions, accepts/rejects | Accepted = payment released |
| System | Tracks reputation, enforces deadlines | Quality incentives maintained |
Posting a Labeling Request
- Navigate to
/app/labor/post - Fill in the request form:
- Title: Clear description of the labeling task
- Category: Image, Text, Audio, Video, RLHF, or Code
- Description: Detailed guidelines for workers
- Data Schema: JSON schema for expected label format
- Price per Label: How much PANDA each accepted label pays
- Total Labels: Number of labels needed
- Reputation Required: Minimum worker reputation (0-100)
- Deadline: When the request expires
- Submit -- your budget (price x labels) is locked in the LaborMarketplace escrow
# On-chain: DataMarketplace contract (contracts/labor/data_marketplace.py)
# Simplified illustration -- the real signature is
# list_request(self, requester, title, category, description, schema, ...)
def list_request(self, requester, title, category, description, schema, budget, price_per_label, reputation_required, deadline, total_labels):
"""Post a new labeling request. Budget is locked in escrow."""
request_id = self.state.next_id
self.state.requests[str(request_id)] = {
"title": title,
"requester": requester,
"category": category,
"budget": budget,
"price_per_label": price_per_label,
"status": "open",
...
}
# Lock funds
self.state.escrow[str(request_id)] = budget
self.state.next_id += 1
Submitting Labels (Workers)
- Browse the marketplace at
/app/labor - Filter by category, pay rate, deadline, or reputation requirement
- Click a request to view details and schema
- Click Claim Task to reserve a spot
- Submit your label data as JSON matching the schema
- Wait for the requester to review
Quality Tips
- Follow the schema exactly -- malformed submissions are auto-rejected
- Higher quality scores improve your reputation
- Reputation unlocks higher-paying tasks
- Consistent accuracy leads to more claims
Earning Reputation
Your on-chain reputation score (0-100) is calculated from:
| Factor | Weight |
|---|---|
| Acceptance rate | 40% |
| Average quality score | 30% |
| Total labels submitted | 20% |
| Account age | 10% |
Higher reputation unlocks:
- Access to premium requests (reputation-gated)
- Priority in task claiming during high demand
- Higher visibility to requesters
Earning from Datasets
Beyond individual labels, workers can earn ongoing revenue:
- Dataset Royalties: If a requester publishes a dataset using your labels, you earn a percentage of future sales
- Quality Bonuses: Some requesters offer bonus payments for top-quality submissions
- Referral Rewards: Invite other workers and earn from their first 10 tasks
Dispute Resolution
If a worker disagrees with a rejection:
- Worker initiates a dispute within 48 hours
- A panel of 3 randomly-selected high-reputation workers reviews the submission
- Majority vote decides the outcome
- If the dispute is upheld, the label is accepted and the requester's rejection rate increases
- Frivolous disputes cost a small stake
# Simplified illustration -- the real signature is
# dispute_rejection(self, worker, label_id) -> Label
def dispute_rejection(self, worker, label_id):
"""Initiate a dispute for a rejected label."""
label = self.state.labels[label_id]
if label["worker"] != worker:
raise ValueError("Only the worker can dispute")
if label["status"] != "rejected":
raise ValueError("Can only dispute rejected labels")
# Mark the label as disputed
label["status"] = "disputed"
Contract Architecture
The marketplace is implemented as a single DataMarketplace contract (contracts/labor/data_marketplace.py). It handles requests, claims, submissions, escrow, reputation, and disputes in one place:
| Responsibility | Where |
|---|---|
| Requests, claims, submissions | DataMarketplace methods (list_request, claim_task, submit_label) |
| Escrow of requester budgets | Held internally; queryable via get_escrow_balance(request_id) |
| Worker reputation | Tracked internally; updated on accept/reject |
| Disputes | dispute_rejection(worker, label_id) |
Categories
| Category | Examples |
|---|---|
| Image | Object detection, segmentation, classification |
| Text | Sentiment analysis, NER, summarization quality |
| Audio | Transcription, speaker identification, emotion |
| Video | Action recognition, temporal annotation |
| RLHF | Preference ranking, helpfulness scoring |
| Code | Code review, bug classification, complexity |
API Reference
These are the methods on the DataMarketplace contract (contracts/labor/data_marketplace.py). The caller/worker/requester address is passed explicitly as the first argument.
Query Methods
get_open_requests(category=None, min_pay=None)-- Browse open requestsget_request(request_id)-- Get request details (returnsDataRequestorNone)get_request_stats(request_id)-- Stats for a single requestget_label(label_id)-- Get a submitted label (returnsLabelorNone)get_worker_balance(worker)-- A worker's withdrawable balanceget_escrow_balance(request_id)-- Escrow still locked for a requestget_price_history(category, epochs=10)-- Per-category price candlesget_market_stats()-- Marketplace-wide statistics (MarketStats)
Call Methods
list_request(requester, title, category, description, schema, ...)-- Post a new labeling request (locks budget in escrow)claim_task(worker, request_id)-- Claim a task as a workersubmit_label(worker, request_id, data_hash, label_data)-- Submit a labelaccept_label(caller, request_id, label_id)-- Accept a submission (requester)reject_label(caller, request_id, label_id, reason)-- Reject a submission (requester)dispute_rejection(worker, label_id)-- Initiate a dispute (worker)register_worker(worker, initial_reputation=0)-- Register a workerwithdraw(worker, amount)-- Withdraw earned balanceadvance_epoch()-- Advance the marketplace epoch (price candles)