Skip to content

Task offer API — agents post work offers with locked XLM reward #113

Description

@leocagli

Problem

Agents can only receive tasks from humans via the orchestrator. There is no way for an agent to offload work to another agent and track the result.

API design

POST /api/task-offers
{ "requiredCapability": "run-inference", "payload": {...}, "reward": "0.05 XLM", "deadline": 1750000000 }
? { "offerId": "off_abc", "escrowTx": "..." }

GET /api/task-offers?cap=run-inference   � list open offers
GET /api/task-offers/:id                 � single offer detail
DELETE /api/task-offers/:id              � cancel (refunds escrow, poster only)

Posting an offer locks the reward in the existing Soroban escrow contract. The deadline is enforced server-side: expired unclaimed offers auto-refund.

Schema

interface TaskOffer {
  offerId: string
  postedBy: string           // agentId
  requiredCapability: string
  payload: unknown
  reward: { amount: string; asset: 'XLM' | 'USDC' }
  deadline: number
  status: 'open' | 'claimed' | 'delivered' | 'accepted' | 'disputed' | 'expired'
}

Files to create

  • app/api/task-offers/route.ts
  • app/api/task-offers/[id]/route.ts
  • lib/task-market/offers.ts

Files to touch

  • lib/task-offers/store.ts (new)
  • lib/task-offers/escrow.ts (new: bloqueo y liberación del reward)
  • app/api/task-offers/route.ts (new: POST y GET con filtro por capability)
  • __tests__/task-offers/escrow.test.ts (new)
  • README.md: documentar el ciclo de vida completo

Relación con #114

Esta issue crea las ofertas y bloquea el reward. #114 las reclama, entrega y libera. Definí acá el estado y las transiciones válidas; #114 las consume. Si las dos issues inventan su propia máquina de estados, se van a contradecir.

Out of scope

Acceptance criteria

  • Crear una oferta bloquea el reward antes de publicarla. Una oferta visible siempre tiene fondos respaldándola.
  • Sin saldo suficiente, la oferta no se crea y no queda nada a medias
  • Los estados válidos y sus transiciones están declarados en un solo lugar
  • Una oferta vencida no puede reclamarse, y su reward vuelve al emisor
  • El filtro por capability no expone ofertas de otros estados
  • Dos requests concurrentes con el mismo idempotency key crean una sola oferta
  • Los montos se manejan como enteros en la unidad mínima

Tests

Al menos 5: creación bloquea fondos, saldo insuficiente aborta limpio, una oferta vencida libera el reward, doble POST idempotente crea una, y una transición inválida se rechaza.

Seguridad

Acá hay dinero bloqueado. El invariante que no se puede romper: la suma de rewards bloqueados nunca supera lo que realmente hay depositado. Todo camino que cree una oferta sin bloquear, o que libere dos veces, rompe eso.

Evidencia visual (OBLIGATORIA)

El PR tiene que incluir:

  1. Creación de una oferta con el reward bloqueado, con el balance antes y después
  2. Captura del intento con saldo insuficiente
  3. Salida del test de vencimiento devolviendo el reward

Sin las tres, el PR no se evalúa.

Estimación

Complejidad: alta. Unos 5 archivos, ~8 h.

Metadata

Metadata

Assignees

Labels

GrantFox OSSPart of the GrantFox OSS campaignMaybe RewardedMay be eligible for GrantFox rewardOfficial CampaignOfficial GrantFox campaign issueThird CampaignCampaign: Third Campaignarea: agentsAgent runtime, SDK, lifecyclearea: x402x402 payment protocolmilestone: v0.4Gamification Layer

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions