From 652b3d85f61c2397240d9464af0b77080ca4a2e9 Mon Sep 17 00:00:00 2001 From: a <33371662+Yuandiaodiaodiao@users.noreply.github.com> Date: Thu, 5 Mar 2026 08:37:42 +0800 Subject: [PATCH 1/5] BAP-579: Agent Task Escrow with Outcome Token Settlement --- BAPs/BAP-579.md | 987 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 987 insertions(+) create mode 100644 BAPs/BAP-579.md diff --git a/BAPs/BAP-579.md b/BAPs/BAP-579.md new file mode 100644 index 00000000..bf3c5f48 --- /dev/null +++ b/BAPs/BAP-579.md @@ -0,0 +1,987 @@ +BAP: 579 +Title: Agent Task Escrow with Outcome Token Settlement +Status: Draft +Type: Application +Created: 2026-03-05 +Dependencies: ERC-1155, ERC-8004, BAP-578 + +# BAP-579: Agent Task Escrow with Outcome Token Settlement + +- [BAP-579: Agent Task Escrow with Outcome Token Settlement](#bap-xxx-agent-task-escrow-with-outcome-token-settlement) + - [1. Summary](#1-summary) + - [2. Abstract](#2-abstract) + - [3. Motivation](#3-motivation) + - [3.1 The Settlement Gap](#31-the-settlement-gap) + - [3.2 Current Ecosystem Limitations](#32-current-ecosystem-limitations) + - [3.3 Prediction Market Inspiration](#33-prediction-market-inspiration) + - [3.4 Why a New Standard](#34-why-a-new-standard) + - [4. Specification](#4-specification) + - [4.1 Core Data Structures](#41-core-data-structures) + - [4.2 Task Escrow Interface](#42-task-escrow-interface) + - [4.3 Arbiter Registry Interface](#43-arbiter-registry-interface) + - [4.4 ERC-1155 Outcome Token](#44-erc-1155-outcome-token) + - [4.5 Task Lifecycle & State Machine](#45-task-lifecycle--state-machine) + - [4.6 Settlement Algorithm](#46-settlement-algorithm) + - [4.7 Two-Tier Dispute Mechanism](#47-two-tier-dispute-mechanism) + - [4.8 ERC-8004 Integration](#48-erc-8004-integration) + - [4.9 BAP-578 Integration](#49-bap-578-integration) + - [5. Rationale](#5-rationale) + - [5.1 Design Decisions](#51-design-decisions) + - [5.2 Alternative Approaches Considered](#52-alternative-approaches-considered) + - [6. Backwards Compatibility](#6-backwards-compatibility) + - [7. Test Cases](#7-test-cases) + - [7.1 Task Lifecycle Tests](#71-task-lifecycle-tests) + - [7.2 Outcome Token Tests](#72-outcome-token-tests) + - [7.3 Arbiter & Settlement Tests](#73-arbiter--settlement-tests) + - [7.4 Dispute Tests](#74-dispute-tests) + - [7.5 Security Tests](#75-security-tests) + - [8. Implementation](#8-implementation) + - [9. Security Considerations](#9-security-considerations) + - [9.1 Arbiter Security](#91-arbiter-security) + - [9.2 Economic Security](#92-economic-security) + - [9.3 Smart Contract Security](#93-smart-contract-security) + - [9.4 Timeout Protection](#94-timeout-protection) + - [10. License](#10-license) + +## 1. Summary + +This BNB Chain Application Proposal (BAP) introduces a standardized protocol for **trustless task delegation and settlement between autonomous agents** on BNB Chain. It addresses [The Missing Trust Layer for the Agent Economy](https://www.bnbchain.org/en/blog/the-missing-trust-layer-for-the-agent-economy) by providing a proof-based escrow mechanism where task bounties are locked in a smart contract and represented as transferable ERC-1155 **Outcome Tokens**. Independent **Arbiter Agents** with staked collateral judge task completion on a granular scale, and payouts are distributed proportionally via outcome token redemption. + +The standard builds on top of [ERC-8004](https://eips.ethereum.org/EIPS/eip-8004) (Trustless Agents) for identity and reputation, and [BAP-578](https://github.com/bnb-chain/BEPs/blob/master/BAPs/BAP-578.md) (Non-Fungible Agents) for agent representation, completing the agent economy stack with the missing settlement layer. + +A reference implementation will be available at: [TODO: GitHub repository link] + +## 2. Abstract + +BAP-579 defines a framework for agents to delegate tasks to other agents with cryptographic guarantees of fair payment. The protocol works as follows: + +1. A **Requester** creates a task and locks a bounty in an escrow smart contract. +2. The contract mints two types of ERC-1155 tokens: **OutcomeSuccess** tokens (issued to the worker) and **OutcomeFailed** tokens (retained by the requester). +3. A **Worker** agent accepts and completes the task, submitting a deliverable. +4. One or more **Arbiter** agents — who must stake collateral to participate — evaluate the deliverable and assign a completion rate on a 0–10000 basis point scale. +5. The bounty is split proportionally: OutcomeSuccess holders claim based on the completion rate, OutcomeFailed holders claim the remainder. +6. All outcome tokens are freely transferable before settlement, enabling prediction-market-style position trading. +7. Settlement results are automatically recorded to ERC-8004 reputation and validation registries. + +Key features include: +- **Prediction Market Settlement**: Outcome tokens function like YES/NO positions, with continuous (non-binary) resolution +- **Flexible Arbitration**: Configurable single or multi-arbiter judging with weighted median aggregation +- **Staked Arbiter Accountability**: Arbiters must stake collateral; dishonest judging results in slashing +- **Two-Tier Dispute Resolution**: Tier 1 re-arbitration with escalation to Tier 2 DAO governance +- **Commit-Reveal Judging**: Prevents arbiters from copying each other's evaluations +- **Full ERC-8004 Integration**: Identity gating, reputation feedback, and validation recording +- **Full BAP-578 Integration**: NFA agents can serve as workers/arbiters with learning history updates + +## 3. Motivation + +### 3.1 The Settlement Gap + +AI agents can execute complex tasks autonomously — routing liquidity, processing data, coordinating multi-step workflows. However, when Agent A wants to delegate work to Agent B, a fundamental problem remains: **how do two agents exchange value without trusting each other?** + +As described in BNB Chain's [The Missing Trust Layer for the Agent Economy](https://www.bnbchain.org/en/blog/the-missing-trust-layer-for-the-agent-economy): + +> Most digital commerce still relies on identity, reputation, or legal enforcement. Those tools assume participants are people or organizations with something to lose. Agents, by contrast, may be pseudonymous, temporary, or created for a single task, making traditional trust mechanisms unreliable. + +The answer is a **proof-based escrow layer** — where payment is locked before work begins, and release is tied directly to cryptographic proof of completion. This proposal implements exactly that. + +### 3.2 Current Ecosystem Limitations + +Existing standards address parts of the agent economy stack but leave the settlement layer unresolved: + +#### 3.2.1 ERC-8004 (Identity & Trust) +ERC-8004 provides agent identity, reputation accumulation, and validation recording — but explicitly excludes payments, pricing, and settlement mechanics. It builds the trust infrastructure but has no mechanism to enforce payment based on trust signals. + +#### 3.2.2 BAP-578 (Agent Representation) +BAP-578 defines how agents exist as on-chain entities (NFAs) with lifecycle management and learning capabilities — but does not specify how agents transact for services or how task outcomes are settled. + +#### 3.2.3 Communication Protocols (MCP, A2A) +Model Context Protocol and Agent-to-Agent protocol enable agents to communicate and discover each other — but provide no mechanism for value exchange or settlement. + +#### 3.2.4 The Missing Piece +None of these standards answer the core question: **given a task with a bounty, how do we guarantee fair payment based on verified task completion?** BAP-579 fills this gap. + +### 3.3 Prediction Market Inspiration + +This proposal draws from prediction market mechanics, where outcome resolution and payout distribution are proven primitives: + +| Prediction Market | Agent Task Escrow | +|---|---| +| Event outcome | Task completion degree | +| YES / NO tokens | OutcomeSuccess / OutcomeFailed tokens | +| Oracle resolution | Arbiter judgment | +| Token holders claim payout | Outcome token holders claim bounty | +| Position trading | Transferable outcome tokens | + +The key innovation is treating task completion as a **continuous variable** (0–100%) rather than a binary outcome, enabling proportional payout that is fair to both parties. + +### 3.4 Why a New Standard + +A proof-based escrow layer enables the agent economy to: + +1. **Eliminate requester default risk** — Payment is locked before work begins +2. **Eliminate worker exploitation** — Workers are guaranteed payment proportional to verified output +3. **Incentivize honest arbitration** — Staking and slashing ensure arbiter accountability +4. **Accumulate trust signals** — Every settlement produces on-chain reputation data +5. **Enable financial composability** — Transferable outcome tokens create a financial layer on top of the task economy + +## 4. Specification + +### 4.1 Core Data Structures + +```solidity +enum TaskStatus { + Created, // Task posted, bounty locked, outcome tokens minted + Accepted, // Worker has accepted the task + Submitted, // Worker has submitted deliverable + Judging, // Arbiter(s) are evaluating + Settled, // Completion rate determined, ready for claims + Disputed, // Dispute initiated (Tier 1) + ReJudging, // New arbiters re-evaluating (Tier 1 dispute) + DAOReview, // Escalated to DAO governance (Tier 2 dispute) + Claimed, // All outcome tokens redeemed + Cancelled // Task cancelled before acceptance +} + +struct ArbiterConfig { + uint8 arbiterCount; // Number of arbiters required (1, 3, 5, 7...) + uint16 feeRateBps; // Arbiter fee as basis points of bounty (per arbiter) + address stakeToken; // Token required for arbiter staking (e.g., USDT) + uint256 minArbiterStake; // Minimum stake required to serve as arbiter + uint256 disputeBondAmount; // Bond required to initiate Tier 1 dispute + uint256 daoDisputeBondAmount;// Bond required to escalate to Tier 2 (DAO) + uint16 disputeThresholdBps; // Deviation threshold to overturn judgment (basis points) +} + +struct TaskDeadlines { + uint256 acceptDeadline; // Deadline for a worker to accept + uint256 submitDeadline; // Deadline for worker to submit deliverable + uint256 judgeDeadline; // Deadline for arbiters to submit judgment + uint256 disputeWindow; // Time window after settlement to initiate dispute + uint256 claimDeadline; // Deadline to claim rewards after final settlement +} + +struct Task { + uint256 taskId; + address requester; // Task creator (EOA or contract) + address worker; // Accepted worker (address(0) until accepted) + address bountyToken; // ERC-20 token used for bounty (address(0) for native BNB) + uint256 bountyAmount; // Total bounty locked in escrow + uint256 totalArbiterFee; // Pre-calculated total arbiter fees + string taskURI; // IPFS/Arweave URI to task description + bytes32 taskHash; // Keccak256 hash of task description for integrity + string deliverableURI; // URI to submitted deliverable (set by worker) + bytes32 deliverableHash; // Hash of deliverable for integrity + TaskStatus status; + ArbiterConfig arbiterConfig; + TaskDeadlines deadlines; + uint16 completionRateBps; // Final completion rate (0-10000 basis points) + uint256 outcomeSuccessTokenId; // ERC-1155 token ID for success outcome + uint256 outcomeFailedTokenId; // ERC-1155 token ID for failed outcome + uint256 createdAt; + uint256 settledAt; +} +``` + +### 4.2 Task Escrow Interface + +```solidity +interface ITaskEscrow { + // Events + event TaskCreated( + uint256 indexed taskId, + address indexed requester, + uint256 bountyAmount, + address bountyToken, + uint256 outcomeSuccessTokenId, + uint256 outcomeFailedTokenId + ); + event TaskAccepted(uint256 indexed taskId, address indexed worker); + event DeliverableSubmitted( + uint256 indexed taskId, + address indexed worker, + string deliverableURI, + bytes32 deliverableHash + ); + event JudgmentSubmitted( + uint256 indexed taskId, + address indexed arbiter, + uint16 completionRateBps + ); + event TaskSettled( + uint256 indexed taskId, + uint16 finalCompletionRateBps, + uint256 workerPayout, + uint256 requesterRefund + ); + event RewardClaimed( + uint256 indexed taskId, + address indexed claimer, + uint256 outcomeTokenId, + uint256 amount, + uint256 tokensBurned + ); + event DisputeInitiated( + uint256 indexed taskId, + address indexed disputant, + uint8 tier, + uint256 bondAmount + ); + event TaskCancelled(uint256 indexed taskId, address indexed requester); + + // Task Lifecycle + function createTask( + string calldata taskURI, + bytes32 taskHash, + address bountyToken, + uint256 bountyAmount, + ArbiterConfig calldata arbiterConfig, + TaskDeadlines calldata deadlines + ) external payable returns (uint256 taskId); + + function acceptTask(uint256 taskId) external; + + function submitDeliverable( + uint256 taskId, + string calldata deliverableURI, + bytes32 deliverableHash + ) external; + + function judgeTask( + uint256 taskId, + uint16 completionRateBps, + string calldata evidenceURI, + bytes32 evidenceHash + ) external; + + function claimReward( + uint256 taskId, + uint256 outcomeTokenId, + uint256 amount + ) external; + + function cancelTask(uint256 taskId) external; + function initiateDispute(uint256 taskId, uint8 tier) external; + + // View Functions + function getTask(uint256 taskId) external view returns (Task memory); + function getTaskStatus(uint256 taskId) external view returns (TaskStatus); + function getClaimableAmount(uint256 taskId, uint256 outcomeTokenId, uint256 tokenAmount) + external view returns (uint256); + function getArbiterJudgments(uint256 taskId) + external view returns (address[] memory arbiters, uint16[] memory ratings); +} +``` + +**Function Specifications:** + +- `createTask()`: Locks bounty in escrow. Mints `OUTCOME_TOKEN_SUPPLY` units each of OutcomeSuccess and OutcomeFailed ERC-1155 tokens to `msg.sender`. Status → `Created`. +- `acceptTask()`: Worker accepts the task. Transfers OutcomeSuccess tokens from requester to worker. Worker MUST hold an ERC-8004 `agentId`. Status → `Accepted`. +- `submitDeliverable()`: Worker submits deliverable URI and integrity hash. Only callable by accepted worker. Status → `Submitted`. +- `judgeTask()`: Arbiter submits completion judgment via commit-reveal scheme. When all required arbiters have revealed, triggers settlement. Status → `Judging` → `Settled`. +- `claimReward()`: Burns outcome tokens and transfers proportional share of bounty. Callable by any outcome token holder after settlement. +- `cancelTask()`: Cancels a task in `Created` status. Refunds bounty, burns all outcome tokens. Only callable by requester. +- `initiateDispute()`: Initiates dispute by locking a dispute bond. `tier=1` triggers re-arbitration; `tier=2` escalates to DAO. + +### 4.3 Arbiter Registry Interface + +```solidity +interface IArbiterRegistry { + // Events + event ArbiterStaked( + address indexed arbiter, + address indexed stakeToken, + uint256 amount, + uint256 totalStake + ); + event ArbiterUnstakeInitiated( + address indexed arbiter, + uint256 amount, + uint256 availableAt + ); + event ArbiterUnstaked(address indexed arbiter, uint256 amount); + event ArbiterSlashed( + address indexed arbiter, + uint256 indexed taskId, + uint256 slashAmount, + string reason + ); + event ArbiterRewarded( + address indexed arbiter, + uint256 indexed taskId, + uint256 rewardAmount + ); + + // Staking + function stake(address stakeToken, uint256 amount) external; + function initiateUnstake(address stakeToken, uint256 amount) external; + function completeUnstake(address stakeToken) external; + + // Slashing (only callable by authorized TaskEscrow contracts) + function slash( + address arbiter, + address stakeToken, + uint256 amount, + uint256 taskId, + string calldata reason + ) external; + + // View Functions + function isEligible(address arbiter, address stakeToken, uint256 minStake) + external view returns (bool eligible, uint256 currentStake); + function getArbiterInfo(address arbiter) external view returns ( + uint256 agentId, + uint256 totalStaked, + uint256 activeTaskCount, + uint256 totalJudgments, + uint256 slashCount + ); + function getUnstakeCooldown() external view returns (uint256); +} +``` + +**Staking Requirements:** + +- Arbiters MUST hold an ERC-8004 `agentId` to stake. +- Minimum stake amount is configurable per task via `ArbiterConfig.minArbiterStake`. +- Staking requires a minimum lock period before becoming eligible (prevents flash loan attacks). +- `initiateUnstake()` starts a cooldown period; `completeUnstake()` releases funds after cooldown. +- Cannot unstake while actively assigned to pending tasks. + +### 4.4 ERC-1155 Outcome Token + +Outcome tokens are ERC-1155 tokens minted by the TaskEscrow contract. They are **freely transferable**, enabling secondary market trading similar to prediction market positions. + +#### 4.4.1 Token ID Encoding + +``` +outcomeTokenId = (taskId << 1) | outcomeType + +where: + outcomeType = 0 for OutcomeSuccess + outcomeType = 1 for OutcomeFailed +``` + +#### 4.4.2 Minting & Transfer Rules + +- On `createTask()`: + - Mint `OUTCOME_TOKEN_SUPPLY` units of OutcomeSuccess to requester + - Mint `OUTCOME_TOKEN_SUPPLY` units of OutcomeFailed to requester + - `OUTCOME_TOKEN_SUPPLY` is a protocol constant (e.g., `10000` matching basis point precision) +- On `acceptTask()`: + - Transfer all OutcomeSuccess tokens from requester to worker + +#### 4.4.3 Redemption Formula + +After settlement, outcome token holders call `claimReward()` to burn tokens and receive proportional bounty: + +``` +netBounty = bountyAmount - totalArbiterFee + +For OutcomeSuccess tokens: + claimable = netBounty × completionRateBps / 10000 × (tokensBurned / OUTCOME_TOKEN_SUPPLY) + +For OutcomeFailed tokens: + claimable = netBounty × (10000 - completionRateBps) / 10000 × (tokensBurned / OUTCOME_TOKEN_SUPPLY) +``` + +#### 4.4.4 Transfer Semantics + +Outcome tokens follow standard ERC-1155 `safeTransferFrom` and `safeBatchTransferFrom`. Any address holding outcome tokens at claim time receives the corresponding payout. This enables: + +- **Workers** to sell OutcomeSuccess tokens before settlement to hedge risk +- **Speculators** to buy discounted outcome tokens anticipating high/low completion rates +- **Requesters** to sell OutcomeFailed tokens if confident the worker will deliver + +#### 4.4.5 Metadata + +Each outcome token SHOULD expose metadata via ERC-1155 `uri()`: + +```json +{ + "name": "Task #42 - OutcomeSuccess", + "description": "Redeemable for proportional share of task bounty based on completion rate", + "properties": { + "taskId": 42, + "outcomeType": "success", + "bountyToken": "0x55d398326f99059fF775485246999027B3197955", + "totalBounty": "1000000000000000000000", + "totalSupply": 10000, + "status": "Judging" + } +} +``` + +### 4.5 Task Lifecycle & State Machine + +``` + ┌──────────────────────┐ + │ Created │ + │ (bounty locked, │ + │ tokens minted) │ + └──────┬───────┬────────┘ + acceptTask()│ │ timeout / cancelTask() + │ ▼ + │ ┌──────────┐ + │ │Cancelled │ + ▼ └──────────┘ + ┌──────────┐ + │ Accepted │ + └────┬─────┘ + │ submitDeliverable() + ▼ + ┌──────────┐ + │Submitted │ + └────┬─────┘ + │ arbiter(s) assigned + ▼ + ┌──────────┐ + │ Judging │ (commit-reveal) + └────┬─────┘ + │ all judgments revealed + ▼ + ┌──────────┐ initiateDispute(1) ┌───────────┐ + │ Settled │ ────────────────────► │ Disputed │ + └────┬─────┘ └─────┬─────┘ + │ │ 2× arbiters re-judge + │ ▼ + │ ┌────────────┐ + │ │ ReJudging │ + │ └──────┬─────┘ + │ ┌────────────┴────────────┐ + │ deviation > θ deviation ≤ θ + │ (overturn) (uphold) + │ │ │ + │ ▼ ▼ + │ Settled (new) Settled (old) + │ │ + │ initiateDispute(2) + │ ▼ + │ ┌───────────┐ + │ │ DAOReview │ → Settled (final) + │ └───────────┘ + │ + ▼ + ┌──────────┐ + │ Claimed │ (all outcome tokens burned) + └──────────┘ +``` + +### 4.6 Settlement Algorithm + +#### 4.6.1 Single Arbiter (arbiterCount = 1) + +The arbiter's submitted `completionRateBps` is used directly as the final completion rate. + +#### 4.6.2 Multiple Arbiters (arbiterCount > 1) + +A **weighted median** is computed where each arbiter's weight is derived from their ERC-8004 reputation score: + +``` +Algorithm: Weighted Median + +Input: [(rate_1, weight_1), (rate_2, weight_2), ..., (rate_n, weight_n)] + +1. Sort pairs by rate ascending. +2. Compute totalWeight = sum of all weights. +3. Iterate through sorted pairs, accumulating weight. +4. The weighted median is the rate where cumulative weight + first reaches or exceeds totalWeight / 2. + +If an arbiter has no ERC-8004 reputation data, default weight = 1. +``` + +#### 4.6.3 Fee Distribution + +``` +totalArbiterFee = bountyAmount × feeRateBps / 10000 × arbiterCount + +Each arbiter receives: + arbiterReward = totalArbiterFee / arbiterCount + +netBounty = bountyAmount - totalArbiterFee + +Worker's claimable pool = netBounty × completionRateBps / 10000 +Requester's claimable pool = netBounty × (10000 - completionRateBps) / 10000 +``` + +#### 4.6.4 Numerical Example + +``` +bountyAmount = 1000 USDT +arbiterCount = 3 +feeRateBps = 200 (2% per arbiter) + +totalArbiterFee = 1000 × 200 / 10000 × 3 = 60 USDT +Each arbiter receives: 20 USDT +netBounty = 1000 - 60 = 940 USDT + +Arbiter judgments (with ERC-8004 reputation weights): + Arbiter A: 8500 bps (weight 3) + Arbiter B: 7000 bps (weight 1) + Arbiter C: 8200 bps (weight 2) + +Sorted: [(7000, w=1), (8200, w=2), (8500, w=3)] +totalWeight = 6, median threshold = 3 +Cumulative: 1 → 3 → weighted median = 8200 bps + +Final completionRateBps = 8200 + +Worker claimable pool: 940 × 8200 / 10000 = 770.80 USDT +Requester claimable pool: 940 × 1800 / 10000 = 169.20 USDT +``` + +### 4.7 Two-Tier Dispute Mechanism + +#### 4.7.1 Tier 1: Re-Arbitration + +1. Either worker or requester calls `initiateDispute(taskId, tier=1)` within `disputeWindow`. +2. Disputant locks `disputeBondAmount` in the escrow contract. +3. System assigns `2 × arbiterCount` **new** arbiters (originals excluded). +4. New arbiters independently judge via the same commit-reveal process. +5. A new `completionRateBps` (the **review rate**) is computed via weighted median. +6. Resolution: + +``` +deviation = abs(reviewRate - originalRate) + +If deviation > disputeThresholdBps: + → Original judgment OVERTURNED + → Final completionRateBps = reviewRate + → Original arbiters' stakes SLASHED (proportional to deviation) + → Disputant's bond REFUNDED + → Slash proceeds: 50% to disputant, 50% to new arbiters + +If deviation ≤ disputeThresholdBps: + → Original judgment UPHELD + → Final completionRateBps = originalRate + → Disputant's bond FORFEITED (distributed to original arbiters) +``` + +#### 4.7.2 Tier 2: DAO Escalation + +1. After Tier 1, if still unsatisfied, disputant calls `initiateDispute(taskId, tier=2)`. +2. Requires `daoDisputeBondAmount` (significantly higher than Tier 1). +3. Dispute escalated to DAO governance vote. +4. DAO members vote on final `completionRateBps`. +5. DAO decision is **final and irreversible**. + +``` +If DAO overturns Tier 1: + → Tier 1 re-arbiters may be slashed + → Disputant's DAO bond refunded + → Final completionRateBps = DAO-determined rate + +If DAO upholds Tier 1: + → Disputant's DAO bond forfeited (to protocol treasury) +``` + +#### 4.7.3 Commit-Reveal for Arbiter Judgments + +To prevent arbiters from copying each other's judgments: + +``` +Phase 1 — Commit: + Each arbiter submits: keccak256(abi.encodePacked(taskId, completionRateBps, salt)) + +Phase 2 — Reveal: + Each arbiter reveals: (completionRateBps, salt) + Contract verifies the reveal matches the commitment. + +Failure to reveal within deadline: + → Judgment excluded + → Portion of arbiter's stake forfeited as penalty +``` + +### 4.8 ERC-8004 Integration + +#### 4.8.1 Identity Requirement + +Workers and arbiters MUST hold a valid ERC-8004 `agentId` via the Identity Registry. Requesters MAY operate without an `agentId` (allowing any EOA or contract to post tasks). + +```solidity +interface IERC8004Gate { + function verifyAgentIdentity(address account) + external view returns (bool hasIdentity, uint256 agentId); + + function getReputationSummary(uint256 agentId, string calldata tag) + external view returns (uint64 count, int128 avgScore); +} +``` + +#### 4.8.2 Reputation Feedback (Post-Settlement) + +Upon settlement, the TaskEscrow contract SHOULD call the ERC-8004 Reputation Registry: + +```solidity +// Record worker's completion rate as reputation signal +reputationRegistry.giveFeedback( + workerAgentId, + int128(completionRateBps), // value + 2, // valueDecimals (bps / 100 = %) + "task-completion", // tag1 + taskId.toString(), // tag2 + taskURI, // endpoint + evidenceURI, // feedbackURI + evidenceHash // feedbackHash +); +``` + +#### 4.8.3 Validation Registry (Arbiter Records) + +Each arbiter judgment is recorded in the ERC-8004 Validation Registry: + +```solidity +validationRegistry.validationResponse( + taskHash, // requestHash + uint8(completionRateBps / 100), // response (0-100) + evidenceURI, // responseURI + evidenceHash, // responseHash + "task-arbitration" // tag +); +``` + +#### 4.8.4 Reputation-Based Gating (Optional) + +Task creators MAY set minimum reputation thresholds: + +```solidity +struct ReputationGate { + string tag; // Reputation domain (e.g., "task-completion") + uint64 minFeedbackCount; // Minimum feedback entries required + int128 minAvgScore; // Minimum average score (fixed-point) + uint8 scoreDecimals; // Decimal precision of minAvgScore +} +``` + +### 4.9 BAP-578 Integration + +#### 4.9.1 NFA as Worker + +A BAP-578 Non-Fungible Agent can serve as a task worker: + +```solidity +// 1. NFA owner sets TaskEscrow-compatible logic contract +nfa.setLogicAddress(nfaTokenId, taskEscrowLogicAddress); + +// 2. Task acceptance triggers NFA action execution +nfa.executeAction(nfaTokenId, abi.encode("acceptTask", taskId)); +``` + +#### 4.9.2 Task History as Learning Data + +When a task is settled, the result SHOULD be recorded to the NFA's learning module: + +```solidity +// Record task completion as an interaction +learningModule.recordInteraction( + nfaTokenId, + "task-completed", + completionRateBps >= 5000 // success threshold +); + +// Update learning tree with task experience +learningModule.updateLearning(nfaTokenId, LearningUpdate({ + previousRoot: currentRoot, + newRoot: newRoot, + proof: merkleProof, + metadata: keccak256(abi.encode(taskId, completionRateBps)) +})); +``` + +#### 4.9.3 NFA Metadata Extension + +NFAs serving as workers or arbiters MAY extend their metadata: + +```json +{ + "persona": "{...}", + "experience": "Specialized data processing agent with 95% avg completion rate", + "capabilities": { + "taskEscrow": { + "acceptsTasks": true, + "taskTypes": ["data-processing", "code-review", "content-generation"], + "minBounty": "10000000000000000000", + "maxBounty": "1000000000000000000000", + "avgCompletionRate": 9500 + } + } +} +``` + +## 5. Rationale + +### 5.1 Design Decisions + +#### 5.1.1 ERC-1155 for Outcome Tokens +ERC-1155's semi-fungible model is ideal: all OutcomeSuccess tokens for one task are interchangeable, but different tasks have distinct tokens. Batch minting/transfer reduces gas costs. Significantly cheaper than deploying separate ERC-20 contracts per task. + +#### 5.1.2 Transferable Outcome Tokens +Transferability enables price discovery (secondary markets reveal completion expectations), risk hedging (workers can sell partial positions), liquidity, and DeFi composability (outcome tokens as collateral). Transferability does not compromise settlement fairness — payout depends solely on completion rate, not token holder identity. + +#### 5.1.3 Basis Points (0–10000) +Basis points provide 0.01% granularity, critical for large bounties. Integer arithmetic avoids floating-point rounding in Solidity. Basis points are the industry standard for financial contracts. + +#### 5.1.4 Two-Tier Dispute +Cost-proportional escalation: Tier 1 (re-arbitration) is cheap and handles most disputes. Tier 2 (DAO) is expensive but provides finality. The threat of slashing keeps arbiters honest without requiring DAO involvement for routine disputes. + +#### 5.1.5 Arbiter Staking +Staking ensures skin-in-the-game, provides Sybil resistance through capital requirements, and is configurable per task (high-value tasks require more stake). + +### 5.2 Alternative Approaches Considered + +| Approach | Decision | Reason | +|---|---|---| +| Binary completion (pass/fail) | Rejected | Too coarse; unfair for partial work | +| Single ERC-20 per task | Rejected | Prohibitive gas costs at scale | +| Non-transferable outcome tokens | Rejected | Eliminates price discovery and risk hedging | +| Single-tier dispute only | Rejected | No finality guarantee | +| No arbiter staking | Rejected | No accountability; enables corrupt judging | +| Mean aggregation (multi-arbiter) | Rejected | Vulnerable to outlier manipulation; weighted median is more robust | + +## 6. Backwards Compatibility + +BAP-579 is fully compatible with existing standards: + +- **ERC-1155**: Outcome tokens are standard ERC-1155 tokens. They work with all ERC-1155 wallets, marketplaces, and DeFi protocols. +- **ERC-8004**: Uses the Identity Registry for agent verification, Reputation Registry for post-settlement feedback, and Validation Registry for arbiter records. No modifications to ERC-8004 contracts required. +- **BAP-578**: NFA agents participate as workers/arbiters via their existing `executeAction()` interface. Task history integrates with the Learning Module. No modifications to BAP-578 contracts required. +- **EOA Compatibility**: Requesters do not need to be agents — any EOA or smart contract can create tasks and hold outcome tokens. +- **ERC-20 Compatibility**: Any ERC-20 token can serve as the bounty token (or native BNB). + +## 7. Test Cases + +### 7.1 Task Lifecycle Tests + +```solidity +// Test complete task lifecycle +function testFullLifecycle() public { + // Create task with 1000 USDT bounty + uint256 taskId = escrow.createTask( + "ipfs://task-description", + keccak256("task content"), + USDT_ADDRESS, + 1000e18, + defaultArbiterConfig, + defaultDeadlines + ); + + // Verify tokens minted + assertEq(outcomeToken.balanceOf(requester, successTokenId), OUTCOME_TOKEN_SUPPLY); + assertEq(outcomeToken.balanceOf(requester, failedTokenId), OUTCOME_TOKEN_SUPPLY); + + // Worker accepts + vm.prank(worker); + escrow.acceptTask(taskId); + assertEq(outcomeToken.balanceOf(worker, successTokenId), OUTCOME_TOKEN_SUPPLY); + assertEq(escrow.getTaskStatus(taskId), TaskStatus.Accepted); + + // Worker submits + vm.prank(worker); + escrow.submitDeliverable(taskId, "ipfs://deliverable", keccak256("deliverable")); + assertEq(escrow.getTaskStatus(taskId), TaskStatus.Submitted); +} + +// Test task cancellation +function testCancelTask() public { + uint256 taskId = escrow.createTask(...); + + vm.prank(requester); + escrow.cancelTask(taskId); + + assertEq(escrow.getTaskStatus(taskId), TaskStatus.Cancelled); + assertEq(USDT.balanceOf(requester), originalBalance); // bounty refunded +} +``` + +### 7.2 Outcome Token Tests + +```solidity +// Test outcome token transferability +function testOutcomeTokenTransfer() public { + uint256 taskId = createAndAcceptTask(); + + // Worker transfers half their OutcomeSuccess tokens to a third party + vm.prank(worker); + outcomeToken.safeTransferFrom(worker, thirdParty, successTokenId, 5000, ""); + + assertEq(outcomeToken.balanceOf(worker, successTokenId), 5000); + assertEq(outcomeToken.balanceOf(thirdParty, successTokenId), 5000); +} + +// Test proportional claim after transfer +function testProportionalClaim() public { + uint256 taskId = createSettledTask(8000); // 80% completion + + // Worker holds 5000/10000 OutcomeSuccess tokens + // Third party holds 5000/10000 OutcomeSuccess tokens + + vm.prank(worker); + escrow.claimReward(taskId, successTokenId, 5000); + // Worker receives: netBounty × 80% × 50% = 376 USDT + + vm.prank(thirdParty); + escrow.claimReward(taskId, successTokenId, 5000); + // Third party receives: netBounty × 80% × 50% = 376 USDT +} +``` + +### 7.3 Arbiter & Settlement Tests + +```solidity +// Test single arbiter settlement +function testSingleArbiterSettlement() public { + uint256 taskId = createSubmittedTask(arbiterCount: 1); + + vm.prank(arbiter); + escrow.judgeTask(taskId, 8200, "ipfs://evidence", keccak256("evidence")); + + Task memory task = escrow.getTask(taskId); + assertEq(task.completionRateBps, 8200); + assertEq(task.status, TaskStatus.Settled); +} + +// Test multi-arbiter weighted median +function testWeightedMedian() public { + uint256 taskId = createSubmittedTask(arbiterCount: 3); + + // Submit judgments (commit-reveal omitted for brevity) + judgeAs(arbiterA, taskId, 8500); // weight 3 + judgeAs(arbiterB, taskId, 7000); // weight 1 + judgeAs(arbiterC, taskId, 8200); // weight 2 + + Task memory task = escrow.getTask(taskId); + assertEq(task.completionRateBps, 8200); // weighted median +} +``` + +### 7.4 Dispute Tests + +```solidity +// Test Tier 1 dispute — overturn +function testTier1DisputeOverturn() public { + uint256 taskId = createSettledTask(5000); // original: 50% + + vm.prank(worker); + escrow.initiateDispute(taskId, 1); + assertEq(escrow.getTaskStatus(taskId), TaskStatus.Disputed); + + // New arbiters judge at 9000 (deviation > threshold) + settleReJudging(taskId, 9000); + + Task memory task = escrow.getTask(taskId); + assertEq(task.completionRateBps, 9000); // overturned + // Verify original arbiters slashed + // Verify disputant bond refunded +} + +// Test Tier 2 DAO escalation +function testTier2DAOEscalation() public { + uint256 taskId = createTier1ResolvedTask(); + + vm.prank(worker); + escrow.initiateDispute(taskId, 2); + assertEq(escrow.getTaskStatus(taskId), TaskStatus.DAOReview); +} +``` + +### 7.5 Security Tests + +```solidity +// Test unauthorized access +function testUnauthorizedAcceptTask() public { + uint256 taskId = escrow.createTask(...); + + vm.prank(addressWithoutAgentId); + vm.expectRevert("BAP-579: worker must have ERC-8004 agentId"); + escrow.acceptTask(taskId); +} + +// Test arbiter without sufficient stake +function testInsufficientStake() public { + vm.prank(understaked_arbiter); + vm.expectRevert("BAP-579: insufficient arbiter stake"); + escrow.judgeTask(taskId, 8000, "", bytes32(0)); +} + +// Test claim before settlement +function testClaimBeforeSettlement() public { + uint256 taskId = createAcceptedTask(); + + vm.prank(worker); + vm.expectRevert("BAP-579: task not settled"); + escrow.claimReward(taskId, successTokenId, 10000); +} + +// Test reentrancy protection +function testReentrancyProtection() public { + // Deploy malicious contract that re-enters on claimReward + MaliciousReceiver attacker = new MaliciousReceiver(address(escrow)); + + vm.prank(address(attacker)); + vm.expectRevert("ReentrancyGuard: reentrant call"); + escrow.claimReward(taskId, successTokenId, 10000); +} +``` + +## 8. Implementation + +A reference implementation will be available at: [TODO: GitHub repository link] + +The implementation will include: +- **TaskEscrow.sol**: Core task lifecycle, escrow logic, settlement algorithm +- **ArbiterRegistry.sol**: Arbiter staking, eligibility checking, slashing +- **OutcomeToken.sol**: ERC-1155 token contract for outcome tokens +- **ERC8004Gate.sol**: Integration adapter for ERC-8004 identity, reputation, and validation registries +- **Interfaces**: `ITaskEscrow.sol`, `IArbiterRegistry.sol`, `IERC8004Gate.sol` +- **Deployment scripts** for BNB Chain Mainnet (Chain ID 56) and Testnet (Chain ID 97) +- **Comprehensive test suite** covering all test cases in Section 7 + +### Dependencies + +- OpenZeppelin: `ERC1155`, `ERC1155Supply`, `ReentrancyGuard`, `Pausable`, `AccessControl` +- ERC-8004: Identity Registry, Reputation Registry, Validation Registry +- BAP-578: `IBAP578`, `ILearningModule` (optional) + +### Gas Optimization + +- Outcome token IDs deterministically derived from `taskId` (no storage mapping needed) +- Batch operations for multi-arbiter judgment submission +- Minimal on-chain storage; task descriptions and deliverables stored via URI + hash +- Commit-reveal uses `bytes32` commitments (single storage slot) + +## 9. Security Considerations + +### 9.1 Arbiter Security + +- **Collusion Prevention**: Commit-reveal scheme prevents arbiters from seeing each other's judgments. Weighted median (not mean) resists outlier manipulation. +- **Sybil Resistance**: Minimum stake requirements make Sybil attacks capital-intensive. ERC-8004 identity adds friction to account creation. +- **Front-Running Prevention**: Mandatory commit-reveal; failure to reveal results in stake penalty and judgment exclusion. +- **Accountability**: Slashing on successful disputes creates financial risk for dishonest arbiters. ERC-8004 reputation tracking makes repeat offenders identifiable. + +### 9.2 Economic Security + +- **Outcome Token Integrity**: Wash trading cannot affect settlement — completion rate is determined solely by arbiter judgment, not token prices. +- **Flash Loan Prevention**: Arbiter staking requires minimum lock period before eligibility. The `initiateUnstake` → cooldown → `completeUnstake` pattern prevents flash-loan manipulation. +- **Fee Predictability**: Total arbiter fees are calculated and deducted at task creation time, ensuring no hidden costs. + +### 9.3 Smart Contract Security + +- **Reentrancy Protection**: All fund-transferring functions (`claimReward`, `cancelTask`, `slash`) MUST use `ReentrancyGuard` and follow checks-effects-interactions pattern. +- **Integer Overflow**: Use Solidity ≥0.8.0 built-in overflow checks. Basis point arithmetic validated to prevent overflow in multiplication. +- **Access Control**: Role-based access via OpenZeppelin `AccessControl`. Only authorized TaskEscrow contracts can call `slash()` on ArbiterRegistry. + +### 9.4 Timeout Protection + +Each phase has a deadline enforced by the contract: + +| Phase | On Timeout | +|---|---| +| Accept deadline | Task auto-cancels, bounty refunded to requester | +| Submit deadline | Task auto-settles at 0% (full refund to requester) | +| Judge deadline | Non-responding arbiters excluded and penalized; settlement proceeds with available judgments | +| Dispute window | Settlement becomes final and irreversible | +| Claim deadline | Unclaimed funds forwarded to protocol treasury | + +## 10. License + +The content is licensed under [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 54ed70b2bbab30822e1d49f2e5cdda26dc7e3308 Mon Sep 17 00:00:00 2001 From: a <33371662+Yuandiaodiaodiao@users.noreply.github.com> Date: Thu, 5 Mar 2026 08:40:01 +0800 Subject: [PATCH 2/5] Rename BAP-579 to BAP-671 (matching PR number) --- BAPs/BAP-579.md | 987 ------------------------------------------------ 1 file changed, 987 deletions(-) delete mode 100644 BAPs/BAP-579.md diff --git a/BAPs/BAP-579.md b/BAPs/BAP-579.md deleted file mode 100644 index bf3c5f48..00000000 --- a/BAPs/BAP-579.md +++ /dev/null @@ -1,987 +0,0 @@ -BAP: 579 -Title: Agent Task Escrow with Outcome Token Settlement -Status: Draft -Type: Application -Created: 2026-03-05 -Dependencies: ERC-1155, ERC-8004, BAP-578 - -# BAP-579: Agent Task Escrow with Outcome Token Settlement - -- [BAP-579: Agent Task Escrow with Outcome Token Settlement](#bap-xxx-agent-task-escrow-with-outcome-token-settlement) - - [1. Summary](#1-summary) - - [2. Abstract](#2-abstract) - - [3. Motivation](#3-motivation) - - [3.1 The Settlement Gap](#31-the-settlement-gap) - - [3.2 Current Ecosystem Limitations](#32-current-ecosystem-limitations) - - [3.3 Prediction Market Inspiration](#33-prediction-market-inspiration) - - [3.4 Why a New Standard](#34-why-a-new-standard) - - [4. Specification](#4-specification) - - [4.1 Core Data Structures](#41-core-data-structures) - - [4.2 Task Escrow Interface](#42-task-escrow-interface) - - [4.3 Arbiter Registry Interface](#43-arbiter-registry-interface) - - [4.4 ERC-1155 Outcome Token](#44-erc-1155-outcome-token) - - [4.5 Task Lifecycle & State Machine](#45-task-lifecycle--state-machine) - - [4.6 Settlement Algorithm](#46-settlement-algorithm) - - [4.7 Two-Tier Dispute Mechanism](#47-two-tier-dispute-mechanism) - - [4.8 ERC-8004 Integration](#48-erc-8004-integration) - - [4.9 BAP-578 Integration](#49-bap-578-integration) - - [5. Rationale](#5-rationale) - - [5.1 Design Decisions](#51-design-decisions) - - [5.2 Alternative Approaches Considered](#52-alternative-approaches-considered) - - [6. Backwards Compatibility](#6-backwards-compatibility) - - [7. Test Cases](#7-test-cases) - - [7.1 Task Lifecycle Tests](#71-task-lifecycle-tests) - - [7.2 Outcome Token Tests](#72-outcome-token-tests) - - [7.3 Arbiter & Settlement Tests](#73-arbiter--settlement-tests) - - [7.4 Dispute Tests](#74-dispute-tests) - - [7.5 Security Tests](#75-security-tests) - - [8. Implementation](#8-implementation) - - [9. Security Considerations](#9-security-considerations) - - [9.1 Arbiter Security](#91-arbiter-security) - - [9.2 Economic Security](#92-economic-security) - - [9.3 Smart Contract Security](#93-smart-contract-security) - - [9.4 Timeout Protection](#94-timeout-protection) - - [10. License](#10-license) - -## 1. Summary - -This BNB Chain Application Proposal (BAP) introduces a standardized protocol for **trustless task delegation and settlement between autonomous agents** on BNB Chain. It addresses [The Missing Trust Layer for the Agent Economy](https://www.bnbchain.org/en/blog/the-missing-trust-layer-for-the-agent-economy) by providing a proof-based escrow mechanism where task bounties are locked in a smart contract and represented as transferable ERC-1155 **Outcome Tokens**. Independent **Arbiter Agents** with staked collateral judge task completion on a granular scale, and payouts are distributed proportionally via outcome token redemption. - -The standard builds on top of [ERC-8004](https://eips.ethereum.org/EIPS/eip-8004) (Trustless Agents) for identity and reputation, and [BAP-578](https://github.com/bnb-chain/BEPs/blob/master/BAPs/BAP-578.md) (Non-Fungible Agents) for agent representation, completing the agent economy stack with the missing settlement layer. - -A reference implementation will be available at: [TODO: GitHub repository link] - -## 2. Abstract - -BAP-579 defines a framework for agents to delegate tasks to other agents with cryptographic guarantees of fair payment. The protocol works as follows: - -1. A **Requester** creates a task and locks a bounty in an escrow smart contract. -2. The contract mints two types of ERC-1155 tokens: **OutcomeSuccess** tokens (issued to the worker) and **OutcomeFailed** tokens (retained by the requester). -3. A **Worker** agent accepts and completes the task, submitting a deliverable. -4. One or more **Arbiter** agents — who must stake collateral to participate — evaluate the deliverable and assign a completion rate on a 0–10000 basis point scale. -5. The bounty is split proportionally: OutcomeSuccess holders claim based on the completion rate, OutcomeFailed holders claim the remainder. -6. All outcome tokens are freely transferable before settlement, enabling prediction-market-style position trading. -7. Settlement results are automatically recorded to ERC-8004 reputation and validation registries. - -Key features include: -- **Prediction Market Settlement**: Outcome tokens function like YES/NO positions, with continuous (non-binary) resolution -- **Flexible Arbitration**: Configurable single or multi-arbiter judging with weighted median aggregation -- **Staked Arbiter Accountability**: Arbiters must stake collateral; dishonest judging results in slashing -- **Two-Tier Dispute Resolution**: Tier 1 re-arbitration with escalation to Tier 2 DAO governance -- **Commit-Reveal Judging**: Prevents arbiters from copying each other's evaluations -- **Full ERC-8004 Integration**: Identity gating, reputation feedback, and validation recording -- **Full BAP-578 Integration**: NFA agents can serve as workers/arbiters with learning history updates - -## 3. Motivation - -### 3.1 The Settlement Gap - -AI agents can execute complex tasks autonomously — routing liquidity, processing data, coordinating multi-step workflows. However, when Agent A wants to delegate work to Agent B, a fundamental problem remains: **how do two agents exchange value without trusting each other?** - -As described in BNB Chain's [The Missing Trust Layer for the Agent Economy](https://www.bnbchain.org/en/blog/the-missing-trust-layer-for-the-agent-economy): - -> Most digital commerce still relies on identity, reputation, or legal enforcement. Those tools assume participants are people or organizations with something to lose. Agents, by contrast, may be pseudonymous, temporary, or created for a single task, making traditional trust mechanisms unreliable. - -The answer is a **proof-based escrow layer** — where payment is locked before work begins, and release is tied directly to cryptographic proof of completion. This proposal implements exactly that. - -### 3.2 Current Ecosystem Limitations - -Existing standards address parts of the agent economy stack but leave the settlement layer unresolved: - -#### 3.2.1 ERC-8004 (Identity & Trust) -ERC-8004 provides agent identity, reputation accumulation, and validation recording — but explicitly excludes payments, pricing, and settlement mechanics. It builds the trust infrastructure but has no mechanism to enforce payment based on trust signals. - -#### 3.2.2 BAP-578 (Agent Representation) -BAP-578 defines how agents exist as on-chain entities (NFAs) with lifecycle management and learning capabilities — but does not specify how agents transact for services or how task outcomes are settled. - -#### 3.2.3 Communication Protocols (MCP, A2A) -Model Context Protocol and Agent-to-Agent protocol enable agents to communicate and discover each other — but provide no mechanism for value exchange or settlement. - -#### 3.2.4 The Missing Piece -None of these standards answer the core question: **given a task with a bounty, how do we guarantee fair payment based on verified task completion?** BAP-579 fills this gap. - -### 3.3 Prediction Market Inspiration - -This proposal draws from prediction market mechanics, where outcome resolution and payout distribution are proven primitives: - -| Prediction Market | Agent Task Escrow | -|---|---| -| Event outcome | Task completion degree | -| YES / NO tokens | OutcomeSuccess / OutcomeFailed tokens | -| Oracle resolution | Arbiter judgment | -| Token holders claim payout | Outcome token holders claim bounty | -| Position trading | Transferable outcome tokens | - -The key innovation is treating task completion as a **continuous variable** (0–100%) rather than a binary outcome, enabling proportional payout that is fair to both parties. - -### 3.4 Why a New Standard - -A proof-based escrow layer enables the agent economy to: - -1. **Eliminate requester default risk** — Payment is locked before work begins -2. **Eliminate worker exploitation** — Workers are guaranteed payment proportional to verified output -3. **Incentivize honest arbitration** — Staking and slashing ensure arbiter accountability -4. **Accumulate trust signals** — Every settlement produces on-chain reputation data -5. **Enable financial composability** — Transferable outcome tokens create a financial layer on top of the task economy - -## 4. Specification - -### 4.1 Core Data Structures - -```solidity -enum TaskStatus { - Created, // Task posted, bounty locked, outcome tokens minted - Accepted, // Worker has accepted the task - Submitted, // Worker has submitted deliverable - Judging, // Arbiter(s) are evaluating - Settled, // Completion rate determined, ready for claims - Disputed, // Dispute initiated (Tier 1) - ReJudging, // New arbiters re-evaluating (Tier 1 dispute) - DAOReview, // Escalated to DAO governance (Tier 2 dispute) - Claimed, // All outcome tokens redeemed - Cancelled // Task cancelled before acceptance -} - -struct ArbiterConfig { - uint8 arbiterCount; // Number of arbiters required (1, 3, 5, 7...) - uint16 feeRateBps; // Arbiter fee as basis points of bounty (per arbiter) - address stakeToken; // Token required for arbiter staking (e.g., USDT) - uint256 minArbiterStake; // Minimum stake required to serve as arbiter - uint256 disputeBondAmount; // Bond required to initiate Tier 1 dispute - uint256 daoDisputeBondAmount;// Bond required to escalate to Tier 2 (DAO) - uint16 disputeThresholdBps; // Deviation threshold to overturn judgment (basis points) -} - -struct TaskDeadlines { - uint256 acceptDeadline; // Deadline for a worker to accept - uint256 submitDeadline; // Deadline for worker to submit deliverable - uint256 judgeDeadline; // Deadline for arbiters to submit judgment - uint256 disputeWindow; // Time window after settlement to initiate dispute - uint256 claimDeadline; // Deadline to claim rewards after final settlement -} - -struct Task { - uint256 taskId; - address requester; // Task creator (EOA or contract) - address worker; // Accepted worker (address(0) until accepted) - address bountyToken; // ERC-20 token used for bounty (address(0) for native BNB) - uint256 bountyAmount; // Total bounty locked in escrow - uint256 totalArbiterFee; // Pre-calculated total arbiter fees - string taskURI; // IPFS/Arweave URI to task description - bytes32 taskHash; // Keccak256 hash of task description for integrity - string deliverableURI; // URI to submitted deliverable (set by worker) - bytes32 deliverableHash; // Hash of deliverable for integrity - TaskStatus status; - ArbiterConfig arbiterConfig; - TaskDeadlines deadlines; - uint16 completionRateBps; // Final completion rate (0-10000 basis points) - uint256 outcomeSuccessTokenId; // ERC-1155 token ID for success outcome - uint256 outcomeFailedTokenId; // ERC-1155 token ID for failed outcome - uint256 createdAt; - uint256 settledAt; -} -``` - -### 4.2 Task Escrow Interface - -```solidity -interface ITaskEscrow { - // Events - event TaskCreated( - uint256 indexed taskId, - address indexed requester, - uint256 bountyAmount, - address bountyToken, - uint256 outcomeSuccessTokenId, - uint256 outcomeFailedTokenId - ); - event TaskAccepted(uint256 indexed taskId, address indexed worker); - event DeliverableSubmitted( - uint256 indexed taskId, - address indexed worker, - string deliverableURI, - bytes32 deliverableHash - ); - event JudgmentSubmitted( - uint256 indexed taskId, - address indexed arbiter, - uint16 completionRateBps - ); - event TaskSettled( - uint256 indexed taskId, - uint16 finalCompletionRateBps, - uint256 workerPayout, - uint256 requesterRefund - ); - event RewardClaimed( - uint256 indexed taskId, - address indexed claimer, - uint256 outcomeTokenId, - uint256 amount, - uint256 tokensBurned - ); - event DisputeInitiated( - uint256 indexed taskId, - address indexed disputant, - uint8 tier, - uint256 bondAmount - ); - event TaskCancelled(uint256 indexed taskId, address indexed requester); - - // Task Lifecycle - function createTask( - string calldata taskURI, - bytes32 taskHash, - address bountyToken, - uint256 bountyAmount, - ArbiterConfig calldata arbiterConfig, - TaskDeadlines calldata deadlines - ) external payable returns (uint256 taskId); - - function acceptTask(uint256 taskId) external; - - function submitDeliverable( - uint256 taskId, - string calldata deliverableURI, - bytes32 deliverableHash - ) external; - - function judgeTask( - uint256 taskId, - uint16 completionRateBps, - string calldata evidenceURI, - bytes32 evidenceHash - ) external; - - function claimReward( - uint256 taskId, - uint256 outcomeTokenId, - uint256 amount - ) external; - - function cancelTask(uint256 taskId) external; - function initiateDispute(uint256 taskId, uint8 tier) external; - - // View Functions - function getTask(uint256 taskId) external view returns (Task memory); - function getTaskStatus(uint256 taskId) external view returns (TaskStatus); - function getClaimableAmount(uint256 taskId, uint256 outcomeTokenId, uint256 tokenAmount) - external view returns (uint256); - function getArbiterJudgments(uint256 taskId) - external view returns (address[] memory arbiters, uint16[] memory ratings); -} -``` - -**Function Specifications:** - -- `createTask()`: Locks bounty in escrow. Mints `OUTCOME_TOKEN_SUPPLY` units each of OutcomeSuccess and OutcomeFailed ERC-1155 tokens to `msg.sender`. Status → `Created`. -- `acceptTask()`: Worker accepts the task. Transfers OutcomeSuccess tokens from requester to worker. Worker MUST hold an ERC-8004 `agentId`. Status → `Accepted`. -- `submitDeliverable()`: Worker submits deliverable URI and integrity hash. Only callable by accepted worker. Status → `Submitted`. -- `judgeTask()`: Arbiter submits completion judgment via commit-reveal scheme. When all required arbiters have revealed, triggers settlement. Status → `Judging` → `Settled`. -- `claimReward()`: Burns outcome tokens and transfers proportional share of bounty. Callable by any outcome token holder after settlement. -- `cancelTask()`: Cancels a task in `Created` status. Refunds bounty, burns all outcome tokens. Only callable by requester. -- `initiateDispute()`: Initiates dispute by locking a dispute bond. `tier=1` triggers re-arbitration; `tier=2` escalates to DAO. - -### 4.3 Arbiter Registry Interface - -```solidity -interface IArbiterRegistry { - // Events - event ArbiterStaked( - address indexed arbiter, - address indexed stakeToken, - uint256 amount, - uint256 totalStake - ); - event ArbiterUnstakeInitiated( - address indexed arbiter, - uint256 amount, - uint256 availableAt - ); - event ArbiterUnstaked(address indexed arbiter, uint256 amount); - event ArbiterSlashed( - address indexed arbiter, - uint256 indexed taskId, - uint256 slashAmount, - string reason - ); - event ArbiterRewarded( - address indexed arbiter, - uint256 indexed taskId, - uint256 rewardAmount - ); - - // Staking - function stake(address stakeToken, uint256 amount) external; - function initiateUnstake(address stakeToken, uint256 amount) external; - function completeUnstake(address stakeToken) external; - - // Slashing (only callable by authorized TaskEscrow contracts) - function slash( - address arbiter, - address stakeToken, - uint256 amount, - uint256 taskId, - string calldata reason - ) external; - - // View Functions - function isEligible(address arbiter, address stakeToken, uint256 minStake) - external view returns (bool eligible, uint256 currentStake); - function getArbiterInfo(address arbiter) external view returns ( - uint256 agentId, - uint256 totalStaked, - uint256 activeTaskCount, - uint256 totalJudgments, - uint256 slashCount - ); - function getUnstakeCooldown() external view returns (uint256); -} -``` - -**Staking Requirements:** - -- Arbiters MUST hold an ERC-8004 `agentId` to stake. -- Minimum stake amount is configurable per task via `ArbiterConfig.minArbiterStake`. -- Staking requires a minimum lock period before becoming eligible (prevents flash loan attacks). -- `initiateUnstake()` starts a cooldown period; `completeUnstake()` releases funds after cooldown. -- Cannot unstake while actively assigned to pending tasks. - -### 4.4 ERC-1155 Outcome Token - -Outcome tokens are ERC-1155 tokens minted by the TaskEscrow contract. They are **freely transferable**, enabling secondary market trading similar to prediction market positions. - -#### 4.4.1 Token ID Encoding - -``` -outcomeTokenId = (taskId << 1) | outcomeType - -where: - outcomeType = 0 for OutcomeSuccess - outcomeType = 1 for OutcomeFailed -``` - -#### 4.4.2 Minting & Transfer Rules - -- On `createTask()`: - - Mint `OUTCOME_TOKEN_SUPPLY` units of OutcomeSuccess to requester - - Mint `OUTCOME_TOKEN_SUPPLY` units of OutcomeFailed to requester - - `OUTCOME_TOKEN_SUPPLY` is a protocol constant (e.g., `10000` matching basis point precision) -- On `acceptTask()`: - - Transfer all OutcomeSuccess tokens from requester to worker - -#### 4.4.3 Redemption Formula - -After settlement, outcome token holders call `claimReward()` to burn tokens and receive proportional bounty: - -``` -netBounty = bountyAmount - totalArbiterFee - -For OutcomeSuccess tokens: - claimable = netBounty × completionRateBps / 10000 × (tokensBurned / OUTCOME_TOKEN_SUPPLY) - -For OutcomeFailed tokens: - claimable = netBounty × (10000 - completionRateBps) / 10000 × (tokensBurned / OUTCOME_TOKEN_SUPPLY) -``` - -#### 4.4.4 Transfer Semantics - -Outcome tokens follow standard ERC-1155 `safeTransferFrom` and `safeBatchTransferFrom`. Any address holding outcome tokens at claim time receives the corresponding payout. This enables: - -- **Workers** to sell OutcomeSuccess tokens before settlement to hedge risk -- **Speculators** to buy discounted outcome tokens anticipating high/low completion rates -- **Requesters** to sell OutcomeFailed tokens if confident the worker will deliver - -#### 4.4.5 Metadata - -Each outcome token SHOULD expose metadata via ERC-1155 `uri()`: - -```json -{ - "name": "Task #42 - OutcomeSuccess", - "description": "Redeemable for proportional share of task bounty based on completion rate", - "properties": { - "taskId": 42, - "outcomeType": "success", - "bountyToken": "0x55d398326f99059fF775485246999027B3197955", - "totalBounty": "1000000000000000000000", - "totalSupply": 10000, - "status": "Judging" - } -} -``` - -### 4.5 Task Lifecycle & State Machine - -``` - ┌──────────────────────┐ - │ Created │ - │ (bounty locked, │ - │ tokens minted) │ - └──────┬───────┬────────┘ - acceptTask()│ │ timeout / cancelTask() - │ ▼ - │ ┌──────────┐ - │ │Cancelled │ - ▼ └──────────┘ - ┌──────────┐ - │ Accepted │ - └────┬─────┘ - │ submitDeliverable() - ▼ - ┌──────────┐ - │Submitted │ - └────┬─────┘ - │ arbiter(s) assigned - ▼ - ┌──────────┐ - │ Judging │ (commit-reveal) - └────┬─────┘ - │ all judgments revealed - ▼ - ┌──────────┐ initiateDispute(1) ┌───────────┐ - │ Settled │ ────────────────────► │ Disputed │ - └────┬─────┘ └─────┬─────┘ - │ │ 2× arbiters re-judge - │ ▼ - │ ┌────────────┐ - │ │ ReJudging │ - │ └──────┬─────┘ - │ ┌────────────┴────────────┐ - │ deviation > θ deviation ≤ θ - │ (overturn) (uphold) - │ │ │ - │ ▼ ▼ - │ Settled (new) Settled (old) - │ │ - │ initiateDispute(2) - │ ▼ - │ ┌───────────┐ - │ │ DAOReview │ → Settled (final) - │ └───────────┘ - │ - ▼ - ┌──────────┐ - │ Claimed │ (all outcome tokens burned) - └──────────┘ -``` - -### 4.6 Settlement Algorithm - -#### 4.6.1 Single Arbiter (arbiterCount = 1) - -The arbiter's submitted `completionRateBps` is used directly as the final completion rate. - -#### 4.6.2 Multiple Arbiters (arbiterCount > 1) - -A **weighted median** is computed where each arbiter's weight is derived from their ERC-8004 reputation score: - -``` -Algorithm: Weighted Median - -Input: [(rate_1, weight_1), (rate_2, weight_2), ..., (rate_n, weight_n)] - -1. Sort pairs by rate ascending. -2. Compute totalWeight = sum of all weights. -3. Iterate through sorted pairs, accumulating weight. -4. The weighted median is the rate where cumulative weight - first reaches or exceeds totalWeight / 2. - -If an arbiter has no ERC-8004 reputation data, default weight = 1. -``` - -#### 4.6.3 Fee Distribution - -``` -totalArbiterFee = bountyAmount × feeRateBps / 10000 × arbiterCount - -Each arbiter receives: - arbiterReward = totalArbiterFee / arbiterCount - -netBounty = bountyAmount - totalArbiterFee - -Worker's claimable pool = netBounty × completionRateBps / 10000 -Requester's claimable pool = netBounty × (10000 - completionRateBps) / 10000 -``` - -#### 4.6.4 Numerical Example - -``` -bountyAmount = 1000 USDT -arbiterCount = 3 -feeRateBps = 200 (2% per arbiter) - -totalArbiterFee = 1000 × 200 / 10000 × 3 = 60 USDT -Each arbiter receives: 20 USDT -netBounty = 1000 - 60 = 940 USDT - -Arbiter judgments (with ERC-8004 reputation weights): - Arbiter A: 8500 bps (weight 3) - Arbiter B: 7000 bps (weight 1) - Arbiter C: 8200 bps (weight 2) - -Sorted: [(7000, w=1), (8200, w=2), (8500, w=3)] -totalWeight = 6, median threshold = 3 -Cumulative: 1 → 3 → weighted median = 8200 bps - -Final completionRateBps = 8200 - -Worker claimable pool: 940 × 8200 / 10000 = 770.80 USDT -Requester claimable pool: 940 × 1800 / 10000 = 169.20 USDT -``` - -### 4.7 Two-Tier Dispute Mechanism - -#### 4.7.1 Tier 1: Re-Arbitration - -1. Either worker or requester calls `initiateDispute(taskId, tier=1)` within `disputeWindow`. -2. Disputant locks `disputeBondAmount` in the escrow contract. -3. System assigns `2 × arbiterCount` **new** arbiters (originals excluded). -4. New arbiters independently judge via the same commit-reveal process. -5. A new `completionRateBps` (the **review rate**) is computed via weighted median. -6. Resolution: - -``` -deviation = abs(reviewRate - originalRate) - -If deviation > disputeThresholdBps: - → Original judgment OVERTURNED - → Final completionRateBps = reviewRate - → Original arbiters' stakes SLASHED (proportional to deviation) - → Disputant's bond REFUNDED - → Slash proceeds: 50% to disputant, 50% to new arbiters - -If deviation ≤ disputeThresholdBps: - → Original judgment UPHELD - → Final completionRateBps = originalRate - → Disputant's bond FORFEITED (distributed to original arbiters) -``` - -#### 4.7.2 Tier 2: DAO Escalation - -1. After Tier 1, if still unsatisfied, disputant calls `initiateDispute(taskId, tier=2)`. -2. Requires `daoDisputeBondAmount` (significantly higher than Tier 1). -3. Dispute escalated to DAO governance vote. -4. DAO members vote on final `completionRateBps`. -5. DAO decision is **final and irreversible**. - -``` -If DAO overturns Tier 1: - → Tier 1 re-arbiters may be slashed - → Disputant's DAO bond refunded - → Final completionRateBps = DAO-determined rate - -If DAO upholds Tier 1: - → Disputant's DAO bond forfeited (to protocol treasury) -``` - -#### 4.7.3 Commit-Reveal for Arbiter Judgments - -To prevent arbiters from copying each other's judgments: - -``` -Phase 1 — Commit: - Each arbiter submits: keccak256(abi.encodePacked(taskId, completionRateBps, salt)) - -Phase 2 — Reveal: - Each arbiter reveals: (completionRateBps, salt) - Contract verifies the reveal matches the commitment. - -Failure to reveal within deadline: - → Judgment excluded - → Portion of arbiter's stake forfeited as penalty -``` - -### 4.8 ERC-8004 Integration - -#### 4.8.1 Identity Requirement - -Workers and arbiters MUST hold a valid ERC-8004 `agentId` via the Identity Registry. Requesters MAY operate without an `agentId` (allowing any EOA or contract to post tasks). - -```solidity -interface IERC8004Gate { - function verifyAgentIdentity(address account) - external view returns (bool hasIdentity, uint256 agentId); - - function getReputationSummary(uint256 agentId, string calldata tag) - external view returns (uint64 count, int128 avgScore); -} -``` - -#### 4.8.2 Reputation Feedback (Post-Settlement) - -Upon settlement, the TaskEscrow contract SHOULD call the ERC-8004 Reputation Registry: - -```solidity -// Record worker's completion rate as reputation signal -reputationRegistry.giveFeedback( - workerAgentId, - int128(completionRateBps), // value - 2, // valueDecimals (bps / 100 = %) - "task-completion", // tag1 - taskId.toString(), // tag2 - taskURI, // endpoint - evidenceURI, // feedbackURI - evidenceHash // feedbackHash -); -``` - -#### 4.8.3 Validation Registry (Arbiter Records) - -Each arbiter judgment is recorded in the ERC-8004 Validation Registry: - -```solidity -validationRegistry.validationResponse( - taskHash, // requestHash - uint8(completionRateBps / 100), // response (0-100) - evidenceURI, // responseURI - evidenceHash, // responseHash - "task-arbitration" // tag -); -``` - -#### 4.8.4 Reputation-Based Gating (Optional) - -Task creators MAY set minimum reputation thresholds: - -```solidity -struct ReputationGate { - string tag; // Reputation domain (e.g., "task-completion") - uint64 minFeedbackCount; // Minimum feedback entries required - int128 minAvgScore; // Minimum average score (fixed-point) - uint8 scoreDecimals; // Decimal precision of minAvgScore -} -``` - -### 4.9 BAP-578 Integration - -#### 4.9.1 NFA as Worker - -A BAP-578 Non-Fungible Agent can serve as a task worker: - -```solidity -// 1. NFA owner sets TaskEscrow-compatible logic contract -nfa.setLogicAddress(nfaTokenId, taskEscrowLogicAddress); - -// 2. Task acceptance triggers NFA action execution -nfa.executeAction(nfaTokenId, abi.encode("acceptTask", taskId)); -``` - -#### 4.9.2 Task History as Learning Data - -When a task is settled, the result SHOULD be recorded to the NFA's learning module: - -```solidity -// Record task completion as an interaction -learningModule.recordInteraction( - nfaTokenId, - "task-completed", - completionRateBps >= 5000 // success threshold -); - -// Update learning tree with task experience -learningModule.updateLearning(nfaTokenId, LearningUpdate({ - previousRoot: currentRoot, - newRoot: newRoot, - proof: merkleProof, - metadata: keccak256(abi.encode(taskId, completionRateBps)) -})); -``` - -#### 4.9.3 NFA Metadata Extension - -NFAs serving as workers or arbiters MAY extend their metadata: - -```json -{ - "persona": "{...}", - "experience": "Specialized data processing agent with 95% avg completion rate", - "capabilities": { - "taskEscrow": { - "acceptsTasks": true, - "taskTypes": ["data-processing", "code-review", "content-generation"], - "minBounty": "10000000000000000000", - "maxBounty": "1000000000000000000000", - "avgCompletionRate": 9500 - } - } -} -``` - -## 5. Rationale - -### 5.1 Design Decisions - -#### 5.1.1 ERC-1155 for Outcome Tokens -ERC-1155's semi-fungible model is ideal: all OutcomeSuccess tokens for one task are interchangeable, but different tasks have distinct tokens. Batch minting/transfer reduces gas costs. Significantly cheaper than deploying separate ERC-20 contracts per task. - -#### 5.1.2 Transferable Outcome Tokens -Transferability enables price discovery (secondary markets reveal completion expectations), risk hedging (workers can sell partial positions), liquidity, and DeFi composability (outcome tokens as collateral). Transferability does not compromise settlement fairness — payout depends solely on completion rate, not token holder identity. - -#### 5.1.3 Basis Points (0–10000) -Basis points provide 0.01% granularity, critical for large bounties. Integer arithmetic avoids floating-point rounding in Solidity. Basis points are the industry standard for financial contracts. - -#### 5.1.4 Two-Tier Dispute -Cost-proportional escalation: Tier 1 (re-arbitration) is cheap and handles most disputes. Tier 2 (DAO) is expensive but provides finality. The threat of slashing keeps arbiters honest without requiring DAO involvement for routine disputes. - -#### 5.1.5 Arbiter Staking -Staking ensures skin-in-the-game, provides Sybil resistance through capital requirements, and is configurable per task (high-value tasks require more stake). - -### 5.2 Alternative Approaches Considered - -| Approach | Decision | Reason | -|---|---|---| -| Binary completion (pass/fail) | Rejected | Too coarse; unfair for partial work | -| Single ERC-20 per task | Rejected | Prohibitive gas costs at scale | -| Non-transferable outcome tokens | Rejected | Eliminates price discovery and risk hedging | -| Single-tier dispute only | Rejected | No finality guarantee | -| No arbiter staking | Rejected | No accountability; enables corrupt judging | -| Mean aggregation (multi-arbiter) | Rejected | Vulnerable to outlier manipulation; weighted median is more robust | - -## 6. Backwards Compatibility - -BAP-579 is fully compatible with existing standards: - -- **ERC-1155**: Outcome tokens are standard ERC-1155 tokens. They work with all ERC-1155 wallets, marketplaces, and DeFi protocols. -- **ERC-8004**: Uses the Identity Registry for agent verification, Reputation Registry for post-settlement feedback, and Validation Registry for arbiter records. No modifications to ERC-8004 contracts required. -- **BAP-578**: NFA agents participate as workers/arbiters via their existing `executeAction()` interface. Task history integrates with the Learning Module. No modifications to BAP-578 contracts required. -- **EOA Compatibility**: Requesters do not need to be agents — any EOA or smart contract can create tasks and hold outcome tokens. -- **ERC-20 Compatibility**: Any ERC-20 token can serve as the bounty token (or native BNB). - -## 7. Test Cases - -### 7.1 Task Lifecycle Tests - -```solidity -// Test complete task lifecycle -function testFullLifecycle() public { - // Create task with 1000 USDT bounty - uint256 taskId = escrow.createTask( - "ipfs://task-description", - keccak256("task content"), - USDT_ADDRESS, - 1000e18, - defaultArbiterConfig, - defaultDeadlines - ); - - // Verify tokens minted - assertEq(outcomeToken.balanceOf(requester, successTokenId), OUTCOME_TOKEN_SUPPLY); - assertEq(outcomeToken.balanceOf(requester, failedTokenId), OUTCOME_TOKEN_SUPPLY); - - // Worker accepts - vm.prank(worker); - escrow.acceptTask(taskId); - assertEq(outcomeToken.balanceOf(worker, successTokenId), OUTCOME_TOKEN_SUPPLY); - assertEq(escrow.getTaskStatus(taskId), TaskStatus.Accepted); - - // Worker submits - vm.prank(worker); - escrow.submitDeliverable(taskId, "ipfs://deliverable", keccak256("deliverable")); - assertEq(escrow.getTaskStatus(taskId), TaskStatus.Submitted); -} - -// Test task cancellation -function testCancelTask() public { - uint256 taskId = escrow.createTask(...); - - vm.prank(requester); - escrow.cancelTask(taskId); - - assertEq(escrow.getTaskStatus(taskId), TaskStatus.Cancelled); - assertEq(USDT.balanceOf(requester), originalBalance); // bounty refunded -} -``` - -### 7.2 Outcome Token Tests - -```solidity -// Test outcome token transferability -function testOutcomeTokenTransfer() public { - uint256 taskId = createAndAcceptTask(); - - // Worker transfers half their OutcomeSuccess tokens to a third party - vm.prank(worker); - outcomeToken.safeTransferFrom(worker, thirdParty, successTokenId, 5000, ""); - - assertEq(outcomeToken.balanceOf(worker, successTokenId), 5000); - assertEq(outcomeToken.balanceOf(thirdParty, successTokenId), 5000); -} - -// Test proportional claim after transfer -function testProportionalClaim() public { - uint256 taskId = createSettledTask(8000); // 80% completion - - // Worker holds 5000/10000 OutcomeSuccess tokens - // Third party holds 5000/10000 OutcomeSuccess tokens - - vm.prank(worker); - escrow.claimReward(taskId, successTokenId, 5000); - // Worker receives: netBounty × 80% × 50% = 376 USDT - - vm.prank(thirdParty); - escrow.claimReward(taskId, successTokenId, 5000); - // Third party receives: netBounty × 80% × 50% = 376 USDT -} -``` - -### 7.3 Arbiter & Settlement Tests - -```solidity -// Test single arbiter settlement -function testSingleArbiterSettlement() public { - uint256 taskId = createSubmittedTask(arbiterCount: 1); - - vm.prank(arbiter); - escrow.judgeTask(taskId, 8200, "ipfs://evidence", keccak256("evidence")); - - Task memory task = escrow.getTask(taskId); - assertEq(task.completionRateBps, 8200); - assertEq(task.status, TaskStatus.Settled); -} - -// Test multi-arbiter weighted median -function testWeightedMedian() public { - uint256 taskId = createSubmittedTask(arbiterCount: 3); - - // Submit judgments (commit-reveal omitted for brevity) - judgeAs(arbiterA, taskId, 8500); // weight 3 - judgeAs(arbiterB, taskId, 7000); // weight 1 - judgeAs(arbiterC, taskId, 8200); // weight 2 - - Task memory task = escrow.getTask(taskId); - assertEq(task.completionRateBps, 8200); // weighted median -} -``` - -### 7.4 Dispute Tests - -```solidity -// Test Tier 1 dispute — overturn -function testTier1DisputeOverturn() public { - uint256 taskId = createSettledTask(5000); // original: 50% - - vm.prank(worker); - escrow.initiateDispute(taskId, 1); - assertEq(escrow.getTaskStatus(taskId), TaskStatus.Disputed); - - // New arbiters judge at 9000 (deviation > threshold) - settleReJudging(taskId, 9000); - - Task memory task = escrow.getTask(taskId); - assertEq(task.completionRateBps, 9000); // overturned - // Verify original arbiters slashed - // Verify disputant bond refunded -} - -// Test Tier 2 DAO escalation -function testTier2DAOEscalation() public { - uint256 taskId = createTier1ResolvedTask(); - - vm.prank(worker); - escrow.initiateDispute(taskId, 2); - assertEq(escrow.getTaskStatus(taskId), TaskStatus.DAOReview); -} -``` - -### 7.5 Security Tests - -```solidity -// Test unauthorized access -function testUnauthorizedAcceptTask() public { - uint256 taskId = escrow.createTask(...); - - vm.prank(addressWithoutAgentId); - vm.expectRevert("BAP-579: worker must have ERC-8004 agentId"); - escrow.acceptTask(taskId); -} - -// Test arbiter without sufficient stake -function testInsufficientStake() public { - vm.prank(understaked_arbiter); - vm.expectRevert("BAP-579: insufficient arbiter stake"); - escrow.judgeTask(taskId, 8000, "", bytes32(0)); -} - -// Test claim before settlement -function testClaimBeforeSettlement() public { - uint256 taskId = createAcceptedTask(); - - vm.prank(worker); - vm.expectRevert("BAP-579: task not settled"); - escrow.claimReward(taskId, successTokenId, 10000); -} - -// Test reentrancy protection -function testReentrancyProtection() public { - // Deploy malicious contract that re-enters on claimReward - MaliciousReceiver attacker = new MaliciousReceiver(address(escrow)); - - vm.prank(address(attacker)); - vm.expectRevert("ReentrancyGuard: reentrant call"); - escrow.claimReward(taskId, successTokenId, 10000); -} -``` - -## 8. Implementation - -A reference implementation will be available at: [TODO: GitHub repository link] - -The implementation will include: -- **TaskEscrow.sol**: Core task lifecycle, escrow logic, settlement algorithm -- **ArbiterRegistry.sol**: Arbiter staking, eligibility checking, slashing -- **OutcomeToken.sol**: ERC-1155 token contract for outcome tokens -- **ERC8004Gate.sol**: Integration adapter for ERC-8004 identity, reputation, and validation registries -- **Interfaces**: `ITaskEscrow.sol`, `IArbiterRegistry.sol`, `IERC8004Gate.sol` -- **Deployment scripts** for BNB Chain Mainnet (Chain ID 56) and Testnet (Chain ID 97) -- **Comprehensive test suite** covering all test cases in Section 7 - -### Dependencies - -- OpenZeppelin: `ERC1155`, `ERC1155Supply`, `ReentrancyGuard`, `Pausable`, `AccessControl` -- ERC-8004: Identity Registry, Reputation Registry, Validation Registry -- BAP-578: `IBAP578`, `ILearningModule` (optional) - -### Gas Optimization - -- Outcome token IDs deterministically derived from `taskId` (no storage mapping needed) -- Batch operations for multi-arbiter judgment submission -- Minimal on-chain storage; task descriptions and deliverables stored via URI + hash -- Commit-reveal uses `bytes32` commitments (single storage slot) - -## 9. Security Considerations - -### 9.1 Arbiter Security - -- **Collusion Prevention**: Commit-reveal scheme prevents arbiters from seeing each other's judgments. Weighted median (not mean) resists outlier manipulation. -- **Sybil Resistance**: Minimum stake requirements make Sybil attacks capital-intensive. ERC-8004 identity adds friction to account creation. -- **Front-Running Prevention**: Mandatory commit-reveal; failure to reveal results in stake penalty and judgment exclusion. -- **Accountability**: Slashing on successful disputes creates financial risk for dishonest arbiters. ERC-8004 reputation tracking makes repeat offenders identifiable. - -### 9.2 Economic Security - -- **Outcome Token Integrity**: Wash trading cannot affect settlement — completion rate is determined solely by arbiter judgment, not token prices. -- **Flash Loan Prevention**: Arbiter staking requires minimum lock period before eligibility. The `initiateUnstake` → cooldown → `completeUnstake` pattern prevents flash-loan manipulation. -- **Fee Predictability**: Total arbiter fees are calculated and deducted at task creation time, ensuring no hidden costs. - -### 9.3 Smart Contract Security - -- **Reentrancy Protection**: All fund-transferring functions (`claimReward`, `cancelTask`, `slash`) MUST use `ReentrancyGuard` and follow checks-effects-interactions pattern. -- **Integer Overflow**: Use Solidity ≥0.8.0 built-in overflow checks. Basis point arithmetic validated to prevent overflow in multiplication. -- **Access Control**: Role-based access via OpenZeppelin `AccessControl`. Only authorized TaskEscrow contracts can call `slash()` on ArbiterRegistry. - -### 9.4 Timeout Protection - -Each phase has a deadline enforced by the contract: - -| Phase | On Timeout | -|---|---| -| Accept deadline | Task auto-cancels, bounty refunded to requester | -| Submit deadline | Task auto-settles at 0% (full refund to requester) | -| Judge deadline | Non-responding arbiters excluded and penalized; settlement proceeds with available judgments | -| Dispute window | Settlement becomes final and irreversible | -| Claim deadline | Unclaimed funds forwarded to protocol treasury | - -## 10. License - -The content is licensed under [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From c88d3b7ac49da5644f92ca61a92014ebea1c8eb9 Mon Sep 17 00:00:00 2001 From: a <33371662+Yuandiaodiaodiao@users.noreply.github.com> Date: Thu, 5 Mar 2026 08:40:08 +0800 Subject: [PATCH 3/5] BAP-671: Agent Task Escrow with Outcome Token Settlement --- BAPs/BAP-671.md | 987 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 987 insertions(+) create mode 100644 BAPs/BAP-671.md diff --git a/BAPs/BAP-671.md b/BAPs/BAP-671.md new file mode 100644 index 00000000..ba2cb312 --- /dev/null +++ b/BAPs/BAP-671.md @@ -0,0 +1,987 @@ +BAP: 671 +Title: Agent Task Escrow with Outcome Token Settlement +Status: Draft +Type: Application +Created: 2026-03-05 +Dependencies: ERC-1155, ERC-8004, BAP-578 + +# BAP-671: Agent Task Escrow with Outcome Token Settlement + +- [BAP-671: Agent Task Escrow with Outcome Token Settlement](#bap-xxx-agent-task-escrow-with-outcome-token-settlement) + - [1. Summary](#1-summary) + - [2. Abstract](#2-abstract) + - [3. Motivation](#3-motivation) + - [3.1 The Settlement Gap](#31-the-settlement-gap) + - [3.2 Current Ecosystem Limitations](#32-current-ecosystem-limitations) + - [3.3 Prediction Market Inspiration](#33-prediction-market-inspiration) + - [3.4 Why a New Standard](#34-why-a-new-standard) + - [4. Specification](#4-specification) + - [4.1 Core Data Structures](#41-core-data-structures) + - [4.2 Task Escrow Interface](#42-task-escrow-interface) + - [4.3 Arbiter Registry Interface](#43-arbiter-registry-interface) + - [4.4 ERC-1155 Outcome Token](#44-erc-1155-outcome-token) + - [4.5 Task Lifecycle & State Machine](#45-task-lifecycle--state-machine) + - [4.6 Settlement Algorithm](#46-settlement-algorithm) + - [4.7 Two-Tier Dispute Mechanism](#47-two-tier-dispute-mechanism) + - [4.8 ERC-8004 Integration](#48-erc-8004-integration) + - [4.9 BAP-578 Integration](#49-bap-578-integration) + - [5. Rationale](#5-rationale) + - [5.1 Design Decisions](#51-design-decisions) + - [5.2 Alternative Approaches Considered](#52-alternative-approaches-considered) + - [6. Backwards Compatibility](#6-backwards-compatibility) + - [7. Test Cases](#7-test-cases) + - [7.1 Task Lifecycle Tests](#71-task-lifecycle-tests) + - [7.2 Outcome Token Tests](#72-outcome-token-tests) + - [7.3 Arbiter & Settlement Tests](#73-arbiter--settlement-tests) + - [7.4 Dispute Tests](#74-dispute-tests) + - [7.5 Security Tests](#75-security-tests) + - [8. Implementation](#8-implementation) + - [9. Security Considerations](#9-security-considerations) + - [9.1 Arbiter Security](#91-arbiter-security) + - [9.2 Economic Security](#92-economic-security) + - [9.3 Smart Contract Security](#93-smart-contract-security) + - [9.4 Timeout Protection](#94-timeout-protection) + - [10. License](#10-license) + +## 1. Summary + +This BNB Chain Application Proposal (BAP) introduces a standardized protocol for **trustless task delegation and settlement between autonomous agents** on BNB Chain. It addresses [The Missing Trust Layer for the Agent Economy](https://www.bnbchain.org/en/blog/the-missing-trust-layer-for-the-agent-economy) by providing a proof-based escrow mechanism where task bounties are locked in a smart contract and represented as transferable ERC-1155 **Outcome Tokens**. Independent **Arbiter Agents** with staked collateral judge task completion on a granular scale, and payouts are distributed proportionally via outcome token redemption. + +The standard builds on top of [ERC-8004](https://eips.ethereum.org/EIPS/eip-8004) (Trustless Agents) for identity and reputation, and [BAP-578](https://github.com/bnb-chain/BEPs/blob/master/BAPs/BAP-578.md) (Non-Fungible Agents) for agent representation, completing the agent economy stack with the missing settlement layer. + +A reference implementation will be available at: [TODO: GitHub repository link] + +## 2. Abstract + +BAP-671 defines a framework for agents to delegate tasks to other agents with cryptographic guarantees of fair payment. The protocol works as follows: + +1. A **Requester** creates a task and locks a bounty in an escrow smart contract. +2. The contract mints two types of ERC-1155 tokens: **OutcomeSuccess** tokens (issued to the worker) and **OutcomeFailed** tokens (retained by the requester). +3. A **Worker** agent accepts and completes the task, submitting a deliverable. +4. One or more **Arbiter** agents — who must stake collateral to participate — evaluate the deliverable and assign a completion rate on a 0–10000 basis point scale. +5. The bounty is split proportionally: OutcomeSuccess holders claim based on the completion rate, OutcomeFailed holders claim the remainder. +6. All outcome tokens are freely transferable before settlement, enabling prediction-market-style position trading. +7. Settlement results are automatically recorded to ERC-8004 reputation and validation registries. + +Key features include: +- **Prediction Market Settlement**: Outcome tokens function like YES/NO positions, with continuous (non-binary) resolution +- **Flexible Arbitration**: Configurable single or multi-arbiter judging with weighted median aggregation +- **Staked Arbiter Accountability**: Arbiters must stake collateral; dishonest judging results in slashing +- **Two-Tier Dispute Resolution**: Tier 1 re-arbitration with escalation to Tier 2 DAO governance +- **Commit-Reveal Judging**: Prevents arbiters from copying each other's evaluations +- **Full ERC-8004 Integration**: Identity gating, reputation feedback, and validation recording +- **Full BAP-578 Integration**: NFA agents can serve as workers/arbiters with learning history updates + +## 3. Motivation + +### 3.1 The Settlement Gap + +AI agents can execute complex tasks autonomously — routing liquidity, processing data, coordinating multi-step workflows. However, when Agent A wants to delegate work to Agent B, a fundamental problem remains: **how do two agents exchange value without trusting each other?** + +As described in BNB Chain's [The Missing Trust Layer for the Agent Economy](https://www.bnbchain.org/en/blog/the-missing-trust-layer-for-the-agent-economy): + +> Most digital commerce still relies on identity, reputation, or legal enforcement. Those tools assume participants are people or organizations with something to lose. Agents, by contrast, may be pseudonymous, temporary, or created for a single task, making traditional trust mechanisms unreliable. + +The answer is a **proof-based escrow layer** — where payment is locked before work begins, and release is tied directly to cryptographic proof of completion. This proposal implements exactly that. + +### 3.2 Current Ecosystem Limitations + +Existing standards address parts of the agent economy stack but leave the settlement layer unresolved: + +#### 3.2.1 ERC-8004 (Identity & Trust) +ERC-8004 provides agent identity, reputation accumulation, and validation recording — but explicitly excludes payments, pricing, and settlement mechanics. It builds the trust infrastructure but has no mechanism to enforce payment based on trust signals. + +#### 3.2.2 BAP-578 (Agent Representation) +BAP-578 defines how agents exist as on-chain entities (NFAs) with lifecycle management and learning capabilities — but does not specify how agents transact for services or how task outcomes are settled. + +#### 3.2.3 Communication Protocols (MCP, A2A) +Model Context Protocol and Agent-to-Agent protocol enable agents to communicate and discover each other — but provide no mechanism for value exchange or settlement. + +#### 3.2.4 The Missing Piece +None of these standards answer the core question: **given a task with a bounty, how do we guarantee fair payment based on verified task completion?** BAP-671 fills this gap. + +### 3.3 Prediction Market Inspiration + +This proposal draws from prediction market mechanics, where outcome resolution and payout distribution are proven primitives: + +| Prediction Market | Agent Task Escrow | +|---|---| +| Event outcome | Task completion degree | +| YES / NO tokens | OutcomeSuccess / OutcomeFailed tokens | +| Oracle resolution | Arbiter judgment | +| Token holders claim payout | Outcome token holders claim bounty | +| Position trading | Transferable outcome tokens | + +The key innovation is treating task completion as a **continuous variable** (0–100%) rather than a binary outcome, enabling proportional payout that is fair to both parties. + +### 3.4 Why a New Standard + +A proof-based escrow layer enables the agent economy to: + +1. **Eliminate requester default risk** — Payment is locked before work begins +2. **Eliminate worker exploitation** — Workers are guaranteed payment proportional to verified output +3. **Incentivize honest arbitration** — Staking and slashing ensure arbiter accountability +4. **Accumulate trust signals** — Every settlement produces on-chain reputation data +5. **Enable financial composability** — Transferable outcome tokens create a financial layer on top of the task economy + +## 4. Specification + +### 4.1 Core Data Structures + +```solidity +enum TaskStatus { + Created, // Task posted, bounty locked, outcome tokens minted + Accepted, // Worker has accepted the task + Submitted, // Worker has submitted deliverable + Judging, // Arbiter(s) are evaluating + Settled, // Completion rate determined, ready for claims + Disputed, // Dispute initiated (Tier 1) + ReJudging, // New arbiters re-evaluating (Tier 1 dispute) + DAOReview, // Escalated to DAO governance (Tier 2 dispute) + Claimed, // All outcome tokens redeemed + Cancelled // Task cancelled before acceptance +} + +struct ArbiterConfig { + uint8 arbiterCount; // Number of arbiters required (1, 3, 5, 7...) + uint16 feeRateBps; // Arbiter fee as basis points of bounty (per arbiter) + address stakeToken; // Token required for arbiter staking (e.g., USDT) + uint256 minArbiterStake; // Minimum stake required to serve as arbiter + uint256 disputeBondAmount; // Bond required to initiate Tier 1 dispute + uint256 daoDisputeBondAmount;// Bond required to escalate to Tier 2 (DAO) + uint16 disputeThresholdBps; // Deviation threshold to overturn judgment (basis points) +} + +struct TaskDeadlines { + uint256 acceptDeadline; // Deadline for a worker to accept + uint256 submitDeadline; // Deadline for worker to submit deliverable + uint256 judgeDeadline; // Deadline for arbiters to submit judgment + uint256 disputeWindow; // Time window after settlement to initiate dispute + uint256 claimDeadline; // Deadline to claim rewards after final settlement +} + +struct Task { + uint256 taskId; + address requester; // Task creator (EOA or contract) + address worker; // Accepted worker (address(0) until accepted) + address bountyToken; // ERC-20 token used for bounty (address(0) for native BNB) + uint256 bountyAmount; // Total bounty locked in escrow + uint256 totalArbiterFee; // Pre-calculated total arbiter fees + string taskURI; // IPFS/Arweave URI to task description + bytes32 taskHash; // Keccak256 hash of task description for integrity + string deliverableURI; // URI to submitted deliverable (set by worker) + bytes32 deliverableHash; // Hash of deliverable for integrity + TaskStatus status; + ArbiterConfig arbiterConfig; + TaskDeadlines deadlines; + uint16 completionRateBps; // Final completion rate (0-10000 basis points) + uint256 outcomeSuccessTokenId; // ERC-1155 token ID for success outcome + uint256 outcomeFailedTokenId; // ERC-1155 token ID for failed outcome + uint256 createdAt; + uint256 settledAt; +} +``` + +### 4.2 Task Escrow Interface + +```solidity +interface ITaskEscrow { + // Events + event TaskCreated( + uint256 indexed taskId, + address indexed requester, + uint256 bountyAmount, + address bountyToken, + uint256 outcomeSuccessTokenId, + uint256 outcomeFailedTokenId + ); + event TaskAccepted(uint256 indexed taskId, address indexed worker); + event DeliverableSubmitted( + uint256 indexed taskId, + address indexed worker, + string deliverableURI, + bytes32 deliverableHash + ); + event JudgmentSubmitted( + uint256 indexed taskId, + address indexed arbiter, + uint16 completionRateBps + ); + event TaskSettled( + uint256 indexed taskId, + uint16 finalCompletionRateBps, + uint256 workerPayout, + uint256 requesterRefund + ); + event RewardClaimed( + uint256 indexed taskId, + address indexed claimer, + uint256 outcomeTokenId, + uint256 amount, + uint256 tokensBurned + ); + event DisputeInitiated( + uint256 indexed taskId, + address indexed disputant, + uint8 tier, + uint256 bondAmount + ); + event TaskCancelled(uint256 indexed taskId, address indexed requester); + + // Task Lifecycle + function createTask( + string calldata taskURI, + bytes32 taskHash, + address bountyToken, + uint256 bountyAmount, + ArbiterConfig calldata arbiterConfig, + TaskDeadlines calldata deadlines + ) external payable returns (uint256 taskId); + + function acceptTask(uint256 taskId) external; + + function submitDeliverable( + uint256 taskId, + string calldata deliverableURI, + bytes32 deliverableHash + ) external; + + function judgeTask( + uint256 taskId, + uint16 completionRateBps, + string calldata evidenceURI, + bytes32 evidenceHash + ) external; + + function claimReward( + uint256 taskId, + uint256 outcomeTokenId, + uint256 amount + ) external; + + function cancelTask(uint256 taskId) external; + function initiateDispute(uint256 taskId, uint8 tier) external; + + // View Functions + function getTask(uint256 taskId) external view returns (Task memory); + function getTaskStatus(uint256 taskId) external view returns (TaskStatus); + function getClaimableAmount(uint256 taskId, uint256 outcomeTokenId, uint256 tokenAmount) + external view returns (uint256); + function getArbiterJudgments(uint256 taskId) + external view returns (address[] memory arbiters, uint16[] memory ratings); +} +``` + +**Function Specifications:** + +- `createTask()`: Locks bounty in escrow. Mints `OUTCOME_TOKEN_SUPPLY` units each of OutcomeSuccess and OutcomeFailed ERC-1155 tokens to `msg.sender`. Status → `Created`. +- `acceptTask()`: Worker accepts the task. Transfers OutcomeSuccess tokens from requester to worker. Worker MUST hold an ERC-8004 `agentId`. Status → `Accepted`. +- `submitDeliverable()`: Worker submits deliverable URI and integrity hash. Only callable by accepted worker. Status → `Submitted`. +- `judgeTask()`: Arbiter submits completion judgment via commit-reveal scheme. When all required arbiters have revealed, triggers settlement. Status → `Judging` → `Settled`. +- `claimReward()`: Burns outcome tokens and transfers proportional share of bounty. Callable by any outcome token holder after settlement. +- `cancelTask()`: Cancels a task in `Created` status. Refunds bounty, burns all outcome tokens. Only callable by requester. +- `initiateDispute()`: Initiates dispute by locking a dispute bond. `tier=1` triggers re-arbitration; `tier=2` escalates to DAO. + +### 4.3 Arbiter Registry Interface + +```solidity +interface IArbiterRegistry { + // Events + event ArbiterStaked( + address indexed arbiter, + address indexed stakeToken, + uint256 amount, + uint256 totalStake + ); + event ArbiterUnstakeInitiated( + address indexed arbiter, + uint256 amount, + uint256 availableAt + ); + event ArbiterUnstaked(address indexed arbiter, uint256 amount); + event ArbiterSlashed( + address indexed arbiter, + uint256 indexed taskId, + uint256 slashAmount, + string reason + ); + event ArbiterRewarded( + address indexed arbiter, + uint256 indexed taskId, + uint256 rewardAmount + ); + + // Staking + function stake(address stakeToken, uint256 amount) external; + function initiateUnstake(address stakeToken, uint256 amount) external; + function completeUnstake(address stakeToken) external; + + // Slashing (only callable by authorized TaskEscrow contracts) + function slash( + address arbiter, + address stakeToken, + uint256 amount, + uint256 taskId, + string calldata reason + ) external; + + // View Functions + function isEligible(address arbiter, address stakeToken, uint256 minStake) + external view returns (bool eligible, uint256 currentStake); + function getArbiterInfo(address arbiter) external view returns ( + uint256 agentId, + uint256 totalStaked, + uint256 activeTaskCount, + uint256 totalJudgments, + uint256 slashCount + ); + function getUnstakeCooldown() external view returns (uint256); +} +``` + +**Staking Requirements:** + +- Arbiters MUST hold an ERC-8004 `agentId` to stake. +- Minimum stake amount is configurable per task via `ArbiterConfig.minArbiterStake`. +- Staking requires a minimum lock period before becoming eligible (prevents flash loan attacks). +- `initiateUnstake()` starts a cooldown period; `completeUnstake()` releases funds after cooldown. +- Cannot unstake while actively assigned to pending tasks. + +### 4.4 ERC-1155 Outcome Token + +Outcome tokens are ERC-1155 tokens minted by the TaskEscrow contract. They are **freely transferable**, enabling secondary market trading similar to prediction market positions. + +#### 4.4.1 Token ID Encoding + +``` +outcomeTokenId = (taskId << 1) | outcomeType + +where: + outcomeType = 0 for OutcomeSuccess + outcomeType = 1 for OutcomeFailed +``` + +#### 4.4.2 Minting & Transfer Rules + +- On `createTask()`: + - Mint `OUTCOME_TOKEN_SUPPLY` units of OutcomeSuccess to requester + - Mint `OUTCOME_TOKEN_SUPPLY` units of OutcomeFailed to requester + - `OUTCOME_TOKEN_SUPPLY` is a protocol constant (e.g., `10000` matching basis point precision) +- On `acceptTask()`: + - Transfer all OutcomeSuccess tokens from requester to worker + +#### 4.4.3 Redemption Formula + +After settlement, outcome token holders call `claimReward()` to burn tokens and receive proportional bounty: + +``` +netBounty = bountyAmount - totalArbiterFee + +For OutcomeSuccess tokens: + claimable = netBounty × completionRateBps / 10000 × (tokensBurned / OUTCOME_TOKEN_SUPPLY) + +For OutcomeFailed tokens: + claimable = netBounty × (10000 - completionRateBps) / 10000 × (tokensBurned / OUTCOME_TOKEN_SUPPLY) +``` + +#### 4.4.4 Transfer Semantics + +Outcome tokens follow standard ERC-1155 `safeTransferFrom` and `safeBatchTransferFrom`. Any address holding outcome tokens at claim time receives the corresponding payout. This enables: + +- **Workers** to sell OutcomeSuccess tokens before settlement to hedge risk +- **Speculators** to buy discounted outcome tokens anticipating high/low completion rates +- **Requesters** to sell OutcomeFailed tokens if confident the worker will deliver + +#### 4.4.5 Metadata + +Each outcome token SHOULD expose metadata via ERC-1155 `uri()`: + +```json +{ + "name": "Task #42 - OutcomeSuccess", + "description": "Redeemable for proportional share of task bounty based on completion rate", + "properties": { + "taskId": 42, + "outcomeType": "success", + "bountyToken": "0x55d398326f99059fF775485246999027B3197955", + "totalBounty": "1000000000000000000000", + "totalSupply": 10000, + "status": "Judging" + } +} +``` + +### 4.5 Task Lifecycle & State Machine + +``` + ┌──────────────────────┐ + │ Created │ + │ (bounty locked, │ + │ tokens minted) │ + └──────┬───────┬────────┘ + acceptTask()│ │ timeout / cancelTask() + │ ▼ + │ ┌──────────┐ + │ │Cancelled │ + ▼ └──────────┘ + ┌──────────┐ + │ Accepted │ + └────┬─────┘ + │ submitDeliverable() + ▼ + ┌──────────┐ + │Submitted │ + └────┬─────┘ + │ arbiter(s) assigned + ▼ + ┌──────────┐ + │ Judging │ (commit-reveal) + └────┬─────┘ + │ all judgments revealed + ▼ + ┌──────────┐ initiateDispute(1) ┌───────────┐ + │ Settled │ ────────────────────► │ Disputed │ + └────┬─────┘ └─────┬─────┘ + │ │ 2× arbiters re-judge + │ ▼ + │ ┌────────────┐ + │ │ ReJudging │ + │ └──────┬─────┘ + │ ┌────────────┴────────────┐ + │ deviation > θ deviation ≤ θ + │ (overturn) (uphold) + │ │ │ + │ ▼ ▼ + │ Settled (new) Settled (old) + │ │ + │ initiateDispute(2) + │ ▼ + │ ┌───────────┐ + │ │ DAOReview │ → Settled (final) + │ └───────────┘ + │ + ▼ + ┌──────────┐ + │ Claimed │ (all outcome tokens burned) + └──────────┘ +``` + +### 4.6 Settlement Algorithm + +#### 4.6.1 Single Arbiter (arbiterCount = 1) + +The arbiter's submitted `completionRateBps` is used directly as the final completion rate. + +#### 4.6.2 Multiple Arbiters (arbiterCount > 1) + +A **weighted median** is computed where each arbiter's weight is derived from their ERC-8004 reputation score: + +``` +Algorithm: Weighted Median + +Input: [(rate_1, weight_1), (rate_2, weight_2), ..., (rate_n, weight_n)] + +1. Sort pairs by rate ascending. +2. Compute totalWeight = sum of all weights. +3. Iterate through sorted pairs, accumulating weight. +4. The weighted median is the rate where cumulative weight + first reaches or exceeds totalWeight / 2. + +If an arbiter has no ERC-8004 reputation data, default weight = 1. +``` + +#### 4.6.3 Fee Distribution + +``` +totalArbiterFee = bountyAmount × feeRateBps / 10000 × arbiterCount + +Each arbiter receives: + arbiterReward = totalArbiterFee / arbiterCount + +netBounty = bountyAmount - totalArbiterFee + +Worker's claimable pool = netBounty × completionRateBps / 10000 +Requester's claimable pool = netBounty × (10000 - completionRateBps) / 10000 +``` + +#### 4.6.4 Numerical Example + +``` +bountyAmount = 1000 USDT +arbiterCount = 3 +feeRateBps = 200 (2% per arbiter) + +totalArbiterFee = 1000 × 200 / 10000 × 3 = 60 USDT +Each arbiter receives: 20 USDT +netBounty = 1000 - 60 = 940 USDT + +Arbiter judgments (with ERC-8004 reputation weights): + Arbiter A: 8500 bps (weight 3) + Arbiter B: 7000 bps (weight 1) + Arbiter C: 8200 bps (weight 2) + +Sorted: [(7000, w=1), (8200, w=2), (8500, w=3)] +totalWeight = 6, median threshold = 3 +Cumulative: 1 → 3 → weighted median = 8200 bps + +Final completionRateBps = 8200 + +Worker claimable pool: 940 × 8200 / 10000 = 770.80 USDT +Requester claimable pool: 940 × 1800 / 10000 = 169.20 USDT +``` + +### 4.7 Two-Tier Dispute Mechanism + +#### 4.7.1 Tier 1: Re-Arbitration + +1. Either worker or requester calls `initiateDispute(taskId, tier=1)` within `disputeWindow`. +2. Disputant locks `disputeBondAmount` in the escrow contract. +3. System assigns `2 × arbiterCount` **new** arbiters (originals excluded). +4. New arbiters independently judge via the same commit-reveal process. +5. A new `completionRateBps` (the **review rate**) is computed via weighted median. +6. Resolution: + +``` +deviation = abs(reviewRate - originalRate) + +If deviation > disputeThresholdBps: + → Original judgment OVERTURNED + → Final completionRateBps = reviewRate + → Original arbiters' stakes SLASHED (proportional to deviation) + → Disputant's bond REFUNDED + → Slash proceeds: 50% to disputant, 50% to new arbiters + +If deviation ≤ disputeThresholdBps: + → Original judgment UPHELD + → Final completionRateBps = originalRate + → Disputant's bond FORFEITED (distributed to original arbiters) +``` + +#### 4.7.2 Tier 2: DAO Escalation + +1. After Tier 1, if still unsatisfied, disputant calls `initiateDispute(taskId, tier=2)`. +2. Requires `daoDisputeBondAmount` (significantly higher than Tier 1). +3. Dispute escalated to DAO governance vote. +4. DAO members vote on final `completionRateBps`. +5. DAO decision is **final and irreversible**. + +``` +If DAO overturns Tier 1: + → Tier 1 re-arbiters may be slashed + → Disputant's DAO bond refunded + → Final completionRateBps = DAO-determined rate + +If DAO upholds Tier 1: + → Disputant's DAO bond forfeited (to protocol treasury) +``` + +#### 4.7.3 Commit-Reveal for Arbiter Judgments + +To prevent arbiters from copying each other's judgments: + +``` +Phase 1 — Commit: + Each arbiter submits: keccak256(abi.encodePacked(taskId, completionRateBps, salt)) + +Phase 2 — Reveal: + Each arbiter reveals: (completionRateBps, salt) + Contract verifies the reveal matches the commitment. + +Failure to reveal within deadline: + → Judgment excluded + → Portion of arbiter's stake forfeited as penalty +``` + +### 4.8 ERC-8004 Integration + +#### 4.8.1 Identity Requirement + +Workers and arbiters MUST hold a valid ERC-8004 `agentId` via the Identity Registry. Requesters MAY operate without an `agentId` (allowing any EOA or contract to post tasks). + +```solidity +interface IERC8004Gate { + function verifyAgentIdentity(address account) + external view returns (bool hasIdentity, uint256 agentId); + + function getReputationSummary(uint256 agentId, string calldata tag) + external view returns (uint64 count, int128 avgScore); +} +``` + +#### 4.8.2 Reputation Feedback (Post-Settlement) + +Upon settlement, the TaskEscrow contract SHOULD call the ERC-8004 Reputation Registry: + +```solidity +// Record worker's completion rate as reputation signal +reputationRegistry.giveFeedback( + workerAgentId, + int128(completionRateBps), // value + 2, // valueDecimals (bps / 100 = %) + "task-completion", // tag1 + taskId.toString(), // tag2 + taskURI, // endpoint + evidenceURI, // feedbackURI + evidenceHash // feedbackHash +); +``` + +#### 4.8.3 Validation Registry (Arbiter Records) + +Each arbiter judgment is recorded in the ERC-8004 Validation Registry: + +```solidity +validationRegistry.validationResponse( + taskHash, // requestHash + uint8(completionRateBps / 100), // response (0-100) + evidenceURI, // responseURI + evidenceHash, // responseHash + "task-arbitration" // tag +); +``` + +#### 4.8.4 Reputation-Based Gating (Optional) + +Task creators MAY set minimum reputation thresholds: + +```solidity +struct ReputationGate { + string tag; // Reputation domain (e.g., "task-completion") + uint64 minFeedbackCount; // Minimum feedback entries required + int128 minAvgScore; // Minimum average score (fixed-point) + uint8 scoreDecimals; // Decimal precision of minAvgScore +} +``` + +### 4.9 BAP-578 Integration + +#### 4.9.1 NFA as Worker + +A BAP-578 Non-Fungible Agent can serve as a task worker: + +```solidity +// 1. NFA owner sets TaskEscrow-compatible logic contract +nfa.setLogicAddress(nfaTokenId, taskEscrowLogicAddress); + +// 2. Task acceptance triggers NFA action execution +nfa.executeAction(nfaTokenId, abi.encode("acceptTask", taskId)); +``` + +#### 4.9.2 Task History as Learning Data + +When a task is settled, the result SHOULD be recorded to the NFA's learning module: + +```solidity +// Record task completion as an interaction +learningModule.recordInteraction( + nfaTokenId, + "task-completed", + completionRateBps >= 5000 // success threshold +); + +// Update learning tree with task experience +learningModule.updateLearning(nfaTokenId, LearningUpdate({ + previousRoot: currentRoot, + newRoot: newRoot, + proof: merkleProof, + metadata: keccak256(abi.encode(taskId, completionRateBps)) +})); +``` + +#### 4.9.3 NFA Metadata Extension + +NFAs serving as workers or arbiters MAY extend their metadata: + +```json +{ + "persona": "{...}", + "experience": "Specialized data processing agent with 95% avg completion rate", + "capabilities": { + "taskEscrow": { + "acceptsTasks": true, + "taskTypes": ["data-processing", "code-review", "content-generation"], + "minBounty": "10000000000000000000", + "maxBounty": "1000000000000000000000", + "avgCompletionRate": 9500 + } + } +} +``` + +## 5. Rationale + +### 5.1 Design Decisions + +#### 5.1.1 ERC-1155 for Outcome Tokens +ERC-1155's semi-fungible model is ideal: all OutcomeSuccess tokens for one task are interchangeable, but different tasks have distinct tokens. Batch minting/transfer reduces gas costs. Significantly cheaper than deploying separate ERC-20 contracts per task. + +#### 5.1.2 Transferable Outcome Tokens +Transferability enables price discovery (secondary markets reveal completion expectations), risk hedging (workers can sell partial positions), liquidity, and DeFi composability (outcome tokens as collateral). Transferability does not compromise settlement fairness — payout depends solely on completion rate, not token holder identity. + +#### 5.1.3 Basis Points (0–10000) +Basis points provide 0.01% granularity, critical for large bounties. Integer arithmetic avoids floating-point rounding in Solidity. Basis points are the industry standard for financial contracts. + +#### 5.1.4 Two-Tier Dispute +Cost-proportional escalation: Tier 1 (re-arbitration) is cheap and handles most disputes. Tier 2 (DAO) is expensive but provides finality. The threat of slashing keeps arbiters honest without requiring DAO involvement for routine disputes. + +#### 5.1.5 Arbiter Staking +Staking ensures skin-in-the-game, provides Sybil resistance through capital requirements, and is configurable per task (high-value tasks require more stake). + +### 5.2 Alternative Approaches Considered + +| Approach | Decision | Reason | +|---|---|---| +| Binary completion (pass/fail) | Rejected | Too coarse; unfair for partial work | +| Single ERC-20 per task | Rejected | Prohibitive gas costs at scale | +| Non-transferable outcome tokens | Rejected | Eliminates price discovery and risk hedging | +| Single-tier dispute only | Rejected | No finality guarantee | +| No arbiter staking | Rejected | No accountability; enables corrupt judging | +| Mean aggregation (multi-arbiter) | Rejected | Vulnerable to outlier manipulation; weighted median is more robust | + +## 6. Backwards Compatibility + +BAP-671 is fully compatible with existing standards: + +- **ERC-1155**: Outcome tokens are standard ERC-1155 tokens. They work with all ERC-1155 wallets, marketplaces, and DeFi protocols. +- **ERC-8004**: Uses the Identity Registry for agent verification, Reputation Registry for post-settlement feedback, and Validation Registry for arbiter records. No modifications to ERC-8004 contracts required. +- **BAP-578**: NFA agents participate as workers/arbiters via their existing `executeAction()` interface. Task history integrates with the Learning Module. No modifications to BAP-578 contracts required. +- **EOA Compatibility**: Requesters do not need to be agents — any EOA or smart contract can create tasks and hold outcome tokens. +- **ERC-20 Compatibility**: Any ERC-20 token can serve as the bounty token (or native BNB). + +## 7. Test Cases + +### 7.1 Task Lifecycle Tests + +```solidity +// Test complete task lifecycle +function testFullLifecycle() public { + // Create task with 1000 USDT bounty + uint256 taskId = escrow.createTask( + "ipfs://task-description", + keccak256("task content"), + USDT_ADDRESS, + 1000e18, + defaultArbiterConfig, + defaultDeadlines + ); + + // Verify tokens minted + assertEq(outcomeToken.balanceOf(requester, successTokenId), OUTCOME_TOKEN_SUPPLY); + assertEq(outcomeToken.balanceOf(requester, failedTokenId), OUTCOME_TOKEN_SUPPLY); + + // Worker accepts + vm.prank(worker); + escrow.acceptTask(taskId); + assertEq(outcomeToken.balanceOf(worker, successTokenId), OUTCOME_TOKEN_SUPPLY); + assertEq(escrow.getTaskStatus(taskId), TaskStatus.Accepted); + + // Worker submits + vm.prank(worker); + escrow.submitDeliverable(taskId, "ipfs://deliverable", keccak256("deliverable")); + assertEq(escrow.getTaskStatus(taskId), TaskStatus.Submitted); +} + +// Test task cancellation +function testCancelTask() public { + uint256 taskId = escrow.createTask(...); + + vm.prank(requester); + escrow.cancelTask(taskId); + + assertEq(escrow.getTaskStatus(taskId), TaskStatus.Cancelled); + assertEq(USDT.balanceOf(requester), originalBalance); // bounty refunded +} +``` + +### 7.2 Outcome Token Tests + +```solidity +// Test outcome token transferability +function testOutcomeTokenTransfer() public { + uint256 taskId = createAndAcceptTask(); + + // Worker transfers half their OutcomeSuccess tokens to a third party + vm.prank(worker); + outcomeToken.safeTransferFrom(worker, thirdParty, successTokenId, 5000, ""); + + assertEq(outcomeToken.balanceOf(worker, successTokenId), 5000); + assertEq(outcomeToken.balanceOf(thirdParty, successTokenId), 5000); +} + +// Test proportional claim after transfer +function testProportionalClaim() public { + uint256 taskId = createSettledTask(8000); // 80% completion + + // Worker holds 5000/10000 OutcomeSuccess tokens + // Third party holds 5000/10000 OutcomeSuccess tokens + + vm.prank(worker); + escrow.claimReward(taskId, successTokenId, 5000); + // Worker receives: netBounty × 80% × 50% = 376 USDT + + vm.prank(thirdParty); + escrow.claimReward(taskId, successTokenId, 5000); + // Third party receives: netBounty × 80% × 50% = 376 USDT +} +``` + +### 7.3 Arbiter & Settlement Tests + +```solidity +// Test single arbiter settlement +function testSingleArbiterSettlement() public { + uint256 taskId = createSubmittedTask(arbiterCount: 1); + + vm.prank(arbiter); + escrow.judgeTask(taskId, 8200, "ipfs://evidence", keccak256("evidence")); + + Task memory task = escrow.getTask(taskId); + assertEq(task.completionRateBps, 8200); + assertEq(task.status, TaskStatus.Settled); +} + +// Test multi-arbiter weighted median +function testWeightedMedian() public { + uint256 taskId = createSubmittedTask(arbiterCount: 3); + + // Submit judgments (commit-reveal omitted for brevity) + judgeAs(arbiterA, taskId, 8500); // weight 3 + judgeAs(arbiterB, taskId, 7000); // weight 1 + judgeAs(arbiterC, taskId, 8200); // weight 2 + + Task memory task = escrow.getTask(taskId); + assertEq(task.completionRateBps, 8200); // weighted median +} +``` + +### 7.4 Dispute Tests + +```solidity +// Test Tier 1 dispute — overturn +function testTier1DisputeOverturn() public { + uint256 taskId = createSettledTask(5000); // original: 50% + + vm.prank(worker); + escrow.initiateDispute(taskId, 1); + assertEq(escrow.getTaskStatus(taskId), TaskStatus.Disputed); + + // New arbiters judge at 9000 (deviation > threshold) + settleReJudging(taskId, 9000); + + Task memory task = escrow.getTask(taskId); + assertEq(task.completionRateBps, 9000); // overturned + // Verify original arbiters slashed + // Verify disputant bond refunded +} + +// Test Tier 2 DAO escalation +function testTier2DAOEscalation() public { + uint256 taskId = createTier1ResolvedTask(); + + vm.prank(worker); + escrow.initiateDispute(taskId, 2); + assertEq(escrow.getTaskStatus(taskId), TaskStatus.DAOReview); +} +``` + +### 7.5 Security Tests + +```solidity +// Test unauthorized access +function testUnauthorizedAcceptTask() public { + uint256 taskId = escrow.createTask(...); + + vm.prank(addressWithoutAgentId); + vm.expectRevert("BAP-671: worker must have ERC-8004 agentId"); + escrow.acceptTask(taskId); +} + +// Test arbiter without sufficient stake +function testInsufficientStake() public { + vm.prank(understaked_arbiter); + vm.expectRevert("BAP-671: insufficient arbiter stake"); + escrow.judgeTask(taskId, 8000, "", bytes32(0)); +} + +// Test claim before settlement +function testClaimBeforeSettlement() public { + uint256 taskId = createAcceptedTask(); + + vm.prank(worker); + vm.expectRevert("BAP-671: task not settled"); + escrow.claimReward(taskId, successTokenId, 10000); +} + +// Test reentrancy protection +function testReentrancyProtection() public { + // Deploy malicious contract that re-enters on claimReward + MaliciousReceiver attacker = new MaliciousReceiver(address(escrow)); + + vm.prank(address(attacker)); + vm.expectRevert("ReentrancyGuard: reentrant call"); + escrow.claimReward(taskId, successTokenId, 10000); +} +``` + +## 8. Implementation + +A reference implementation will be available at: [TODO: GitHub repository link] + +The implementation will include: +- **TaskEscrow.sol**: Core task lifecycle, escrow logic, settlement algorithm +- **ArbiterRegistry.sol**: Arbiter staking, eligibility checking, slashing +- **OutcomeToken.sol**: ERC-1155 token contract for outcome tokens +- **ERC8004Gate.sol**: Integration adapter for ERC-8004 identity, reputation, and validation registries +- **Interfaces**: `ITaskEscrow.sol`, `IArbiterRegistry.sol`, `IERC8004Gate.sol` +- **Deployment scripts** for BNB Chain Mainnet (Chain ID 56) and Testnet (Chain ID 97) +- **Comprehensive test suite** covering all test cases in Section 7 + +### Dependencies + +- OpenZeppelin: `ERC1155`, `ERC1155Supply`, `ReentrancyGuard`, `Pausable`, `AccessControl` +- ERC-8004: Identity Registry, Reputation Registry, Validation Registry +- BAP-578: `IBAP578`, `ILearningModule` (optional) + +### Gas Optimization + +- Outcome token IDs deterministically derived from `taskId` (no storage mapping needed) +- Batch operations for multi-arbiter judgment submission +- Minimal on-chain storage; task descriptions and deliverables stored via URI + hash +- Commit-reveal uses `bytes32` commitments (single storage slot) + +## 9. Security Considerations + +### 9.1 Arbiter Security + +- **Collusion Prevention**: Commit-reveal scheme prevents arbiters from seeing each other's judgments. Weighted median (not mean) resists outlier manipulation. +- **Sybil Resistance**: Minimum stake requirements make Sybil attacks capital-intensive. ERC-8004 identity adds friction to account creation. +- **Front-Running Prevention**: Mandatory commit-reveal; failure to reveal results in stake penalty and judgment exclusion. +- **Accountability**: Slashing on successful disputes creates financial risk for dishonest arbiters. ERC-8004 reputation tracking makes repeat offenders identifiable. + +### 9.2 Economic Security + +- **Outcome Token Integrity**: Wash trading cannot affect settlement — completion rate is determined solely by arbiter judgment, not token prices. +- **Flash Loan Prevention**: Arbiter staking requires minimum lock period before eligibility. The `initiateUnstake` → cooldown → `completeUnstake` pattern prevents flash-loan manipulation. +- **Fee Predictability**: Total arbiter fees are calculated and deducted at task creation time, ensuring no hidden costs. + +### 9.3 Smart Contract Security + +- **Reentrancy Protection**: All fund-transferring functions (`claimReward`, `cancelTask`, `slash`) MUST use `ReentrancyGuard` and follow checks-effects-interactions pattern. +- **Integer Overflow**: Use Solidity ≥0.8.0 built-in overflow checks. Basis point arithmetic validated to prevent overflow in multiplication. +- **Access Control**: Role-based access via OpenZeppelin `AccessControl`. Only authorized TaskEscrow contracts can call `slash()` on ArbiterRegistry. + +### 9.4 Timeout Protection + +Each phase has a deadline enforced by the contract: + +| Phase | On Timeout | +|---|---| +| Accept deadline | Task auto-cancels, bounty refunded to requester | +| Submit deadline | Task auto-settles at 0% (full refund to requester) | +| Judge deadline | Non-responding arbiters excluded and penalized; settlement proceeds with available judgments | +| Dispute window | Settlement becomes final and irreversible | +| Claim deadline | Unclaimed funds forwarded to protocol treasury | + +## 10. License + +The content is licensed under [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From a3c4943ad59b2746c65b5b2948165281489b35e8 Mon Sep 17 00:00:00 2001 From: a <33371662+Yuandiaodiaodiao@users.noreply.github.com> Date: Thu, 5 Mar 2026 08:42:53 +0800 Subject: [PATCH 4/5] Fix: correct TOC anchor link from bap-xxx to bap-671 --- BAPs/BAP-671.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BAPs/BAP-671.md b/BAPs/BAP-671.md index ba2cb312..4d83cddb 100644 --- a/BAPs/BAP-671.md +++ b/BAPs/BAP-671.md @@ -7,7 +7,7 @@ Dependencies: ERC-1155, ERC-8004, BAP-578 # BAP-671: Agent Task Escrow with Outcome Token Settlement -- [BAP-671: Agent Task Escrow with Outcome Token Settlement](#bap-xxx-agent-task-escrow-with-outcome-token-settlement) +- [BAP-671: Agent Task Escrow with Outcome Token Settlement](#bap-671-agent-task-escrow-with-outcome-token-settlement) - [1. Summary](#1-summary) - [2. Abstract](#2-abstract) - [3. Motivation](#3-motivation) From 524232aafb067a248cee5652a3d1537d4b35bc90 Mon Sep 17 00:00:00 2001 From: yuandiaodiaodiao Date: Fri, 6 Mar 2026 04:05:57 +0800 Subject: [PATCH 5/5] feat: add Optimistic Settlement mode to BAP-671 Introduce optimistic-first settlement where tasks auto-settle at 100% unless challenged, bringing in arbiter agents only on dispute to determine completion ratio. This saves arbiter costs for honest tasks. Co-Authored-By: Claude Opus 4.6 --- BAPs/BAP-671.md | 388 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 362 insertions(+), 26 deletions(-) diff --git a/BAPs/BAP-671.md b/BAPs/BAP-671.md index 4d83cddb..d8c94797 100644 --- a/BAPs/BAP-671.md +++ b/BAPs/BAP-671.md @@ -21,12 +21,16 @@ Dependencies: ERC-1155, ERC-8004, BAP-578 - [4.3 Arbiter Registry Interface](#43-arbiter-registry-interface) - [4.4 ERC-1155 Outcome Token](#44-erc-1155-outcome-token) - [4.5 Task Lifecycle & State Machine](#45-task-lifecycle--state-machine) + - [4.5.1 Optimistic Settlement Path](#451-optimistic-settlement-path) + - [4.5.2 Arbitrated Settlement Path](#452-arbitrated-settlement-path-traditional) - [4.6 Settlement Algorithm](#46-settlement-algorithm) + - [4.6.0 Optimistic Settlement](#460-optimistic-settlement-settlementmode--optimistic) - [4.7 Two-Tier Dispute Mechanism](#47-two-tier-dispute-mechanism) - [4.8 ERC-8004 Integration](#48-erc-8004-integration) - [4.9 BAP-578 Integration](#49-bap-578-integration) - [5. Rationale](#5-rationale) - [5.1 Design Decisions](#51-design-decisions) + - [5.1.6 Optimistic-First Settlement](#516-optimistic-first-settlement) - [5.2 Alternative Approaches Considered](#52-alternative-approaches-considered) - [6. Backwards Compatibility](#6-backwards-compatibility) - [7. Test Cases](#7-test-cases) @@ -34,18 +38,24 @@ Dependencies: ERC-1155, ERC-8004, BAP-578 - [7.2 Outcome Token Tests](#72-outcome-token-tests) - [7.3 Arbiter & Settlement Tests](#73-arbiter--settlement-tests) - [7.4 Dispute Tests](#74-dispute-tests) - - [7.5 Security Tests](#75-security-tests) + - [7.5 Optimistic Settlement Tests](#75-optimistic-settlement-tests) + - [7.6 Security Tests](#76-security-tests) - [8. Implementation](#8-implementation) - [9. Security Considerations](#9-security-considerations) - [9.1 Arbiter Security](#91-arbiter-security) - [9.2 Economic Security](#92-economic-security) - [9.3 Smart Contract Security](#93-smart-contract-security) - - [9.4 Timeout Protection](#94-timeout-protection) + - [9.4 Optimistic Settlement Security](#94-optimistic-settlement-security) + - [9.5 Timeout Protection](#95-timeout-protection) - [10. License](#10-license) ## 1. Summary -This BNB Chain Application Proposal (BAP) introduces a standardized protocol for **trustless task delegation and settlement between autonomous agents** on BNB Chain. It addresses [The Missing Trust Layer for the Agent Economy](https://www.bnbchain.org/en/blog/the-missing-trust-layer-for-the-agent-economy) by providing a proof-based escrow mechanism where task bounties are locked in a smart contract and represented as transferable ERC-1155 **Outcome Tokens**. Independent **Arbiter Agents** with staked collateral judge task completion on a granular scale, and payouts are distributed proportionally via outcome token redemption. +This BNB Chain Application Proposal (BAP) introduces a standardized protocol for **trustless task delegation and settlement between autonomous agents** on BNB Chain. It addresses [The Missing Trust Layer for the Agent Economy](https://www.bnbchain.org/en/blog/the-missing-trust-layer-for-the-agent-economy) by providing an **optimistic-first escrow mechanism** where task bounties are locked in a smart contract and represented as transferable ERC-1155 **Outcome Tokens**. + +The protocol defaults to **Optimistic Settlement** — tasks auto-settle at 100% completion unless the requester challenges the deliverable within a time window. Only upon challenge are **Arbiter Agents** with staked collateral brought in to determine the actual completion ratio on a 0–10000 basis point scale. This design, inspired by Optimistic Rollups, eliminates arbiter costs for the vast majority of honest task completions while preserving strong dispute resolution guarantees. + +For high-value or trust-critical tasks, the protocol also supports a traditional **Arbitrated Settlement** mode where arbiter judgment is always required. The standard builds on top of [ERC-8004](https://eips.ethereum.org/EIPS/eip-8004) (Trustless Agents) for identity and reputation, and [BAP-578](https://github.com/bnb-chain/BEPs/blob/master/BAPs/BAP-578.md) (Non-Fungible Agents) for agent representation, completing the agent economy stack with the missing settlement layer. @@ -53,20 +63,27 @@ A reference implementation will be available at: [TODO: GitHub repository link] ## 2. Abstract -BAP-671 defines a framework for agents to delegate tasks to other agents with cryptographic guarantees of fair payment. The protocol works as follows: +BAP-671 defines a framework for agents to delegate tasks to other agents with cryptographic guarantees of fair payment. The protocol supports two settlement modes: + +**Optimistic Mode (Default):** 1. A **Requester** creates a task and locks a bounty in an escrow smart contract. 2. The contract mints two types of ERC-1155 tokens: **OutcomeSuccess** tokens (issued to the worker) and **OutcomeFailed** tokens (retained by the requester). 3. A **Worker** agent accepts and completes the task, submitting a deliverable. -4. One or more **Arbiter** agents — who must stake collateral to participate — evaluate the deliverable and assign a completion rate on a 0–10000 basis point scale. -5. The bounty is split proportionally: OutcomeSuccess holders claim based on the completion rate, OutcomeFailed holders claim the remainder. -6. All outcome tokens are freely transferable before settlement, enabling prediction-market-style position trading. -7. Settlement results are automatically recorded to ERC-8004 reputation and validation registries. +4. A **challenge window** opens. The requester reviews the deliverable off-chain. +5. **If unchallenged**: after the window expires, anyone calls `finalizeOptimistic()` to auto-settle at 100% completion. No arbiter fees are incurred. +6. **If challenged**: the requester locks a challenge bond, and one or more **Arbiter Agents** are brought in to determine the actual completion rate on a 0–10000 basis point scale. The bounty is split proportionally based on the arbiter-determined rate. +7. All outcome tokens are freely transferable before settlement, enabling prediction-market-style position trading. +8. Settlement results are automatically recorded to ERC-8004 reputation and validation registries. + +**Arbitrated Mode (Optional):** Traditional flow where arbiter judgment is always required — suitable for high-value or trust-critical tasks. Key features include: +- **Optimistic-First Settlement**: No arbiter overhead for honest completions; arbiters only on dispute - **Prediction Market Settlement**: Outcome tokens function like YES/NO positions, with continuous (non-binary) resolution - **Flexible Arbitration**: Configurable single or multi-arbiter judging with weighted median aggregation - **Staked Arbiter Accountability**: Arbiters must stake collateral; dishonest judging results in slashing +- **Challenge Bond Economics**: Frivolous challenges are penalized; successful challenges are rewarded - **Two-Tier Dispute Resolution**: Tier 1 re-arbitration with escalation to Tier 2 DAO governance - **Commit-Reveal Judging**: Prevents arbiters from copying each other's evaluations - **Full ERC-8004 Integration**: Identity gating, reputation feedback, and validation recording @@ -129,17 +146,29 @@ A proof-based escrow layer enables the agent economy to: ### 4.1 Core Data Structures ```solidity +enum SettlementMode { + Optimistic, // Default: optimistic settlement, arbiters only on challenge + Arbitrated // Traditional: always requires arbiter judgment +} + enum TaskStatus { - Created, // Task posted, bounty locked, outcome tokens minted - Accepted, // Worker has accepted the task - Submitted, // Worker has submitted deliverable - Judging, // Arbiter(s) are evaluating - Settled, // Completion rate determined, ready for claims - Disputed, // Dispute initiated (Tier 1) - ReJudging, // New arbiters re-evaluating (Tier 1 dispute) - DAOReview, // Escalated to DAO governance (Tier 2 dispute) - Claimed, // All outcome tokens redeemed - Cancelled // Task cancelled before acceptance + Created, // Task posted, bounty locked, outcome tokens minted + Accepted, // Worker has accepted the task + Submitted, // Worker has submitted deliverable + OptimisticReview, // [Optimistic] Deliverable submitted, in challenge window + Judging, // Arbiter(s) are evaluating (triggered by challenge or Arbitrated mode) + Settled, // Completion rate determined, ready for claims + Disputed, // Dispute initiated (Tier 1) + ReJudging, // New arbiters re-evaluating (Tier 1 dispute) + DAOReview, // Escalated to DAO governance (Tier 2 dispute) + Claimed, // All outcome tokens redeemed + Cancelled // Task cancelled before acceptance +} + +struct OptimisticConfig { + uint256 challengeWindow; // Duration of challenge window in seconds (e.g., 86400 = 24h) + uint256 challengeBondAmount; // Bond required to challenge optimistic settlement + uint16 defaultCompletionBps; // Default completion rate if unchallenged (typically 10000 = 100%) } struct ArbiterConfig { @@ -166,19 +195,23 @@ struct Task { address worker; // Accepted worker (address(0) until accepted) address bountyToken; // ERC-20 token used for bounty (address(0) for native BNB) uint256 bountyAmount; // Total bounty locked in escrow - uint256 totalArbiterFee; // Pre-calculated total arbiter fees + uint256 totalArbiterFee; // Pre-calculated total arbiter fees (0 for Optimistic until challenged) string taskURI; // IPFS/Arweave URI to task description bytes32 taskHash; // Keccak256 hash of task description for integrity string deliverableURI; // URI to submitted deliverable (set by worker) bytes32 deliverableHash; // Hash of deliverable for integrity TaskStatus status; + SettlementMode settlementMode; // Optimistic or Arbitrated + OptimisticConfig optimisticConfig; // Config for optimistic mode (ignored if Arbitrated) ArbiterConfig arbiterConfig; TaskDeadlines deadlines; uint16 completionRateBps; // Final completion rate (0-10000 basis points) uint256 outcomeSuccessTokenId; // ERC-1155 token ID for success outcome uint256 outcomeFailedTokenId; // ERC-1155 token ID for failed outcome uint256 createdAt; + uint256 submittedAt; // Timestamp of deliverable submission (for challenge window calc) uint256 settledAt; + address challenger; // Address that challenged optimistic settlement (address(0) if none) } ``` @@ -220,6 +253,15 @@ interface ITaskEscrow { uint256 amount, uint256 tokensBurned ); + event OptimisticChallenged( + uint256 indexed taskId, + address indexed challenger, + uint256 bondAmount + ); + event OptimisticFinalized( + uint256 indexed taskId, + uint16 defaultCompletionBps + ); event DisputeInitiated( uint256 indexed taskId, address indexed disputant, @@ -234,6 +276,8 @@ interface ITaskEscrow { bytes32 taskHash, address bountyToken, uint256 bountyAmount, + SettlementMode settlementMode, + OptimisticConfig calldata optimisticConfig, ArbiterConfig calldata arbiterConfig, TaskDeadlines calldata deadlines ) external payable returns (uint256 taskId); @@ -246,6 +290,11 @@ interface ITaskEscrow { bytes32 deliverableHash ) external; + // Optimistic Settlement + function challengeOptimistic(uint256 taskId) external payable; + function finalizeOptimistic(uint256 taskId) external; + + // Arbitrated Judgment function judgeTask( uint256 taskId, uint16 completionRateBps, @@ -274,13 +323,15 @@ interface ITaskEscrow { **Function Specifications:** -- `createTask()`: Locks bounty in escrow. Mints `OUTCOME_TOKEN_SUPPLY` units each of OutcomeSuccess and OutcomeFailed ERC-1155 tokens to `msg.sender`. Status → `Created`. +- `createTask()`: Locks bounty in escrow. Mints `OUTCOME_TOKEN_SUPPLY` units each of OutcomeSuccess and OutcomeFailed ERC-1155 tokens to `msg.sender`. For `Optimistic` mode, no arbiter fees are pre-deducted. For `Arbitrated` mode, arbiter fees are calculated and reserved. Status → `Created`. - `acceptTask()`: Worker accepts the task. Transfers OutcomeSuccess tokens from requester to worker. Worker MUST hold an ERC-8004 `agentId`. Status → `Accepted`. -- `submitDeliverable()`: Worker submits deliverable URI and integrity hash. Only callable by accepted worker. Status → `Submitted`. +- `submitDeliverable()`: Worker submits deliverable URI and integrity hash. Only callable by accepted worker. Records `submittedAt` timestamp. Status → `OptimisticReview` (if Optimistic mode) or `Submitted` (if Arbitrated mode). +- `challengeOptimistic()`: **[Optimistic only]** Requester challenges the deliverable within the challenge window by locking `challengeBondAmount`. Triggers arbiter assignment and transitions to judging phase. Status → `OptimisticReview` → `Judging`. Only callable by requester during the challenge window (`submittedAt + challengeWindow`). +- `finalizeOptimistic()`: **[Optimistic only]** Callable by anyone after the challenge window expires without a challenge. Auto-settles the task at `defaultCompletionBps` (typically 100%). No arbiter fees deducted. Status → `OptimisticReview` → `Settled`. - `judgeTask()`: Arbiter submits completion judgment via commit-reveal scheme. When all required arbiters have revealed, triggers settlement. Status → `Judging` → `Settled`. - `claimReward()`: Burns outcome tokens and transfers proportional share of bounty. Callable by any outcome token holder after settlement. - `cancelTask()`: Cancels a task in `Created` status. Refunds bounty, burns all outcome tokens. Only callable by requester. -- `initiateDispute()`: Initiates dispute by locking a dispute bond. `tier=1` triggers re-arbitration; `tier=2` escalates to DAO. +- `initiateDispute()`: Initiates dispute by locking a dispute bond. `tier=1` triggers re-arbitration; `tier=2` escalates to DAO. Available after settlement in both Optimistic (post-challenge) and Arbitrated modes. ### 4.3 Arbiter Registry Interface @@ -413,6 +464,80 @@ Each outcome token SHOULD expose metadata via ERC-1155 `uri()`: ### 4.5 Task Lifecycle & State Machine +The state machine supports two settlement paths: **Optimistic** (default) and **Arbitrated**. + +#### 4.5.1 Optimistic Settlement Path + +In Optimistic mode, tasks are assumed to be completed honestly. Arbiters are only invoked if the requester challenges the deliverable during the challenge window. This eliminates arbiter costs for the majority of tasks that complete without dispute. + +``` + ┌──────────────────────┐ + │ Created │ + │ (bounty locked, │ + │ tokens minted) │ + └──────┬───────┬────────┘ + acceptTask()│ │ timeout / cancelTask() + │ ▼ + │ ┌──────────┐ + │ │Cancelled │ + ▼ └──────────┘ + ┌──────────┐ + │ Accepted │ + └────┬─────┘ + │ submitDeliverable() + ▼ + ┌──────────────────┐ + │ OptimisticReview │ (challenge window active) + └───┬──────────┬───┘ + │ │ + no challenge │ │ challengeOptimistic() + + window ends │ │ (requester locks bond) + │ │ + ▼ ▼ + finalizeOptimistic()│ + │ │ + ▼ ▼ + ┌──────────┐ ┌──────────┐ + │ Settled │ │ Judging │ (arbiter(s) assigned) + │ (100%) │ └────┬─────┘ + └────┬─────┘ │ all judgments revealed + │ ▼ + │ ┌──────────┐ initiateDispute(1) ┌───────────┐ + │ │ Settled │ ────────────────────► │ Disputed │ + │ │ (rated) │ └─────┬─────┘ + │ └────┬─────┘ │ + │ │ (same dispute flow + │ │ as Arbitrated mode) + ▼ ▼ + ┌──────────────────┐ + │ Claimed │ (all outcome tokens burned) + └──────────────────┘ +``` + +**Challenge outcome resolution (after Judging):** + +``` +arbiterRate = weighted median of arbiter judgments +challengeThreshold = defaultCompletionBps - arbiterConfig.disputeThresholdBps + +If arbiterRate < challengeThreshold: + → Challenge SUCCEEDED + → completionRateBps = arbiterRate + → Challenger's bond REFUNDED + → Challenger receives bonus from bounty savings (difference × bonusRateBps) + → Arbiter fees deducted from bounty + +If arbiterRate ≥ challengeThreshold: + → Challenge FAILED + → completionRateBps = defaultCompletionBps (100%) + → Challenger's bond FORFEITED to worker + → Arbiter fees deducted from challenger's bond +``` + +#### 4.5.2 Arbitrated Settlement Path (Traditional) + +In Arbitrated mode, every task requires arbiter judgment. This path is unchanged from the original design and is suitable for high-value tasks where the requester prefers upfront verification. + ``` ┌──────────────────────┐ │ Created │ @@ -468,11 +593,94 @@ Each outcome token SHOULD expose metadata via ERC-1155 `uri()`: ### 4.6 Settlement Algorithm -#### 4.6.1 Single Arbiter (arbiterCount = 1) +#### 4.6.0 Optimistic Settlement (SettlementMode = Optimistic) + +**Happy Path (No Challenge):** + +When the challenge window expires without a challenge, `finalizeOptimistic()` settles the task: + +``` +completionRateBps = defaultCompletionBps (typically 10000 = 100%) +netBounty = bountyAmount (no arbiter fees deducted) +totalArbiterFee = 0 + +Worker claimable pool: bountyAmount × defaultCompletionBps / 10000 +Requester claimable pool: bountyAmount × (10000 - defaultCompletionBps) / 10000 +``` + +**Challenged Path:** + +When the requester challenges during the window, the task enters `Judging` and arbiters determine the actual completion rate. After judgment: + +``` +arbiterRate = weighted median of arbiter judgments (see 4.6.1 / 4.6.2) +challengeThreshold = defaultCompletionBps - disputeThresholdBps + +totalArbiterFee = bountyAmount × feeRateBps / 10000 × arbiterCount + +CASE 1: Challenge Succeeded (arbiterRate < challengeThreshold) + completionRateBps = arbiterRate + netBounty = bountyAmount - totalArbiterFee + Challenger's bond → REFUNDED in full + Worker claimable pool: netBounty × arbiterRate / 10000 + Requester claimable pool: netBounty × (10000 - arbiterRate) / 10000 + +CASE 2: Challenge Failed (arbiterRate ≥ challengeThreshold) + completionRateBps = defaultCompletionBps + Arbiter fees → paid from challenger's bond + If challengeBondAmount > totalArbiterFee: + remainder = challengeBondAmount - totalArbiterFee → transferred to worker as compensation + netBounty = bountyAmount (full bounty goes to settlement, no fees deducted from it) + Worker claimable pool: netBounty × defaultCompletionBps / 10000 + Requester claimable pool: netBounty × (10000 - defaultCompletionBps) / 10000 +``` + +**Numerical Example (Optimistic — Challenged, Challenge Succeeds):** + +``` +bountyAmount = 1000 USDT +challengeBondAmount = 100 USDT +arbiterCount = 3 +feeRateBps = 200 (2% per arbiter) +defaultCompletionBps = 10000 (100%) +disputeThresholdBps = 1000 (10%) + +Requester challenges → locks 100 USDT bond +3 arbiters judge: weighted median = 6000 bps (60%) + +challengeThreshold = 10000 - 1000 = 9000 +6000 < 9000 → Challenge SUCCEEDED + +totalArbiterFee = 1000 × 200/10000 × 3 = 60 USDT (paid from bounty) +netBounty = 1000 - 60 = 940 USDT +Challenger's 100 USDT bond → REFUNDED + +Worker claimable pool: 940 × 6000/10000 = 564.00 USDT +Requester claimable pool: 940 × 4000/10000 = 376.00 USDT +``` + +**Numerical Example (Optimistic — Challenged, Challenge Fails):** + +``` +Same setup, but arbiters judge: weighted median = 9500 bps (95%) + +9500 ≥ 9000 → Challenge FAILED + +totalArbiterFee = 60 USDT (paid from challenger's bond) +Challenger's bond remainder: 100 - 60 = 40 USDT → transferred to worker +netBounty = 1000 USDT (untouched) + +Worker claimable pool: 1000 × 10000/10000 = 1000.00 USDT + + 40 USDT compensation from bond = 1040.00 USDT total +Requester claimable pool: 1000 × 0/10000 = 0 USDT + + lost 100 USDT challenge bond +``` + +#### 4.6.1 Arbitrated Settlement — Single Arbiter (arbiterCount = 1) The arbiter's submitted `completionRateBps` is used directly as the final completion rate. -#### 4.6.2 Multiple Arbiters (arbiterCount > 1) +#### 4.6.2 Arbitrated Settlement — Multiple Arbiters (arbiterCount > 1) A **weighted median** is computed where each arbiter's weight is derived from their ERC-8004 reputation score: @@ -727,6 +935,17 @@ Cost-proportional escalation: Tier 1 (re-arbitration) is cheap and handles most #### 5.1.5 Arbiter Staking Staking ensures skin-in-the-game, provides Sybil resistance through capital requirements, and is configurable per task (high-value tasks require more stake). +#### 5.1.6 Optimistic-First Settlement +Requiring arbiter judgment for every task is expensive and slow. In practice, the vast majority of agent tasks will complete honestly — the economic incentive to deliver (reputation gain + payment) outweighs the incentive to cheat (reputation loss + no payment). This mirrors the insight behind Optimistic Rollups: assume validity by default, only verify on challenge. + +Benefits of optimistic settlement: +- **Cost reduction**: Unchallenged tasks incur zero arbiter fees (saving 2–6% of bounty per task) +- **Lower latency**: Workers receive payment at challenge window expiry, not after arbiter evaluation +- **Scalability**: Arbiter capacity is only consumed when genuinely needed +- **Correct incentives**: Challengers must post a bond, deterring frivolous disputes. Workers who deliver honestly are never penalized by arbiter overhead. + +The Arbitrated mode remains available for tasks where the requester demands upfront verification — the protocol does not force optimism on risk-averse participants. + ### 5.2 Alternative Approaches Considered | Approach | Decision | Reason | @@ -737,6 +956,8 @@ Staking ensures skin-in-the-game, provides Sybil resistance through capital requ | Single-tier dispute only | Rejected | No finality guarantee | | No arbiter staking | Rejected | No accountability; enables corrupt judging | | Mean aggregation (multi-arbiter) | Rejected | Vulnerable to outlier manipulation; weighted median is more robust | +| Always-optimistic (no Arbitrated mode) | Rejected | High-value tasks need upfront verification; dual-mode preserves choice | +| Optimistic with fixed penalty (not proportional) | Rejected | Binary penalties discourage partial work; proportional settlement is fairer | ## 6. Backwards Compatibility @@ -884,7 +1105,113 @@ function testTier2DAOEscalation() public { } ``` -### 7.5 Security Tests +### 7.5 Optimistic Settlement Tests + +```solidity +// Test optimistic happy path — no challenge, auto-settle at 100% +function testOptimisticHappyPath() public { + uint256 taskId = escrow.createTask( + "ipfs://task-description", + keccak256("task content"), + USDT_ADDRESS, + 1000e18, + SettlementMode.Optimistic, + OptimisticConfig({ + challengeWindow: 86400, // 24 hours + challengeBondAmount: 100e18, // 100 USDT + defaultCompletionBps: 10000 // 100% + }), + defaultArbiterConfig, + defaultDeadlines + ); + + // Worker accepts and submits + vm.prank(worker); + escrow.acceptTask(taskId); + vm.prank(worker); + escrow.submitDeliverable(taskId, "ipfs://deliverable", keccak256("deliverable")); + assertEq(escrow.getTaskStatus(taskId), TaskStatus.OptimisticReview); + + // Fast-forward past challenge window + vm.warp(block.timestamp + 86401); + + // Anyone can finalize + escrow.finalizeOptimistic(taskId); + + Task memory task = escrow.getTask(taskId); + assertEq(task.completionRateBps, 10000); // 100% + assertEq(task.totalArbiterFee, 0); // no arbiter fees + assertEq(task.status, TaskStatus.Settled); +} + +// Test optimistic challenge — challenge succeeds (low completion) +function testOptimisticChallengeSucceeds() public { + uint256 taskId = createOptimisticSubmittedTask(); + + // Requester challenges within window + vm.prank(requester); + escrow.challengeOptimistic{value: 0}(taskId); + // (bond transferred via ERC-20 approve + transferFrom) + + assertEq(escrow.getTaskStatus(taskId), TaskStatus.Judging); + + // Arbiter judges at 60% (below threshold of 90%) + vm.prank(arbiter); + escrow.judgeTask(taskId, 6000, "ipfs://evidence", keccak256("evidence")); + + Task memory task = escrow.getTask(taskId); + assertEq(task.completionRateBps, 6000); // arbiter-determined rate + // Verify challenger's bond was refunded + // Verify arbiter fees deducted from bounty +} + +// Test optimistic challenge — challenge fails (high completion) +function testOptimisticChallengeFails() public { + uint256 taskId = createOptimisticSubmittedTask(); + + vm.prank(requester); + escrow.challengeOptimistic(taskId); + + // Arbiter judges at 95% (above threshold of 90%) + vm.prank(arbiter); + escrow.judgeTask(taskId, 9500, "ipfs://evidence", keccak256("evidence")); + + Task memory task = escrow.getTask(taskId); + assertEq(task.completionRateBps, 10000); // defaultCompletionBps maintained + // Verify challenger's bond forfeited to worker + // Verify arbiter fees paid from challenger's bond +} + +// Test cannot challenge after window expires +function testCannotChallengeAfterWindow() public { + uint256 taskId = createOptimisticSubmittedTask(); + + vm.warp(block.timestamp + 86401); + + vm.prank(requester); + vm.expectRevert("BAP-671: challenge window expired"); + escrow.challengeOptimistic(taskId); +} + +// Test cannot finalize during active window +function testCannotFinalizeBeforeWindowExpires() public { + uint256 taskId = createOptimisticSubmittedTask(); + + vm.expectRevert("BAP-671: challenge window still active"); + escrow.finalizeOptimistic(taskId); +} + +// Test only requester can challenge +function testOnlyRequesterCanChallenge() public { + uint256 taskId = createOptimisticSubmittedTask(); + + vm.prank(randomAddress); + vm.expectRevert("BAP-671: only requester can challenge"); + escrow.challengeOptimistic(taskId); +} +``` + +### 7.6 Security Tests ```solidity // Test unauthorized access @@ -970,7 +1297,15 @@ The implementation will include: - **Integer Overflow**: Use Solidity ≥0.8.0 built-in overflow checks. Basis point arithmetic validated to prevent overflow in multiplication. - **Access Control**: Role-based access via OpenZeppelin `AccessControl`. Only authorized TaskEscrow contracts can call `slash()` on ArbiterRegistry. -### 9.4 Timeout Protection +### 9.4 Optimistic Settlement Security + +- **Challenge Window Length**: The challenge window represents a critical trade-off. Too short (< 1 hour) and requesters may not have time to evaluate deliverables, especially for complex tasks. Too long (> 7 days) and workers' capital is locked unnecessarily, reducing protocol attractiveness. Recommended default: 24–72 hours, configurable per task. +- **Frivolous Challenge Prevention**: The challenge bond (`challengeBondAmount`) creates a financial cost for challenging. If the challenge fails, the bond is forfeited to the worker, compensating them for the delay. The bond SHOULD be set proportional to the bounty (recommended: 5–15% of bounty). +- **Reputation-Adaptive Windows**: Implementers MAY allow shorter challenge windows for workers with high ERC-8004 reputation scores. A worker with 100+ successful task completions and >95% average score presents lower risk, justifying a shorter window. +- **Griefing Attack Mitigation**: A malicious requester could repeatedly create tasks, let workers complete them, then challenge to impose delays and arbiter costs. Mitigation: (1) challenge bond makes this expensive; (2) failed challenges build negative reputation for the requester; (3) workers can check requester's challenge history via ERC-8004 before accepting tasks. +- **Worker Abandonment**: In Optimistic mode, if a worker submits a low-quality or empty deliverable, the requester's only recourse is to challenge. The challenge bond cost is the "price of insurance" against bad work. To mitigate: (1) use reputation gating to filter workers; (2) set `defaultCompletionBps < 10000` for tasks given to untrusted workers. + +### 9.5 Timeout Protection Each phase has a deadline enforced by the contract: @@ -978,6 +1313,7 @@ Each phase has a deadline enforced by the contract: |---|---| | Accept deadline | Task auto-cancels, bounty refunded to requester | | Submit deadline | Task auto-settles at 0% (full refund to requester) | +| Challenge window (Optimistic) | Task eligible for `finalizeOptimistic()` at defaultCompletionBps | | Judge deadline | Non-responding arbiters excluded and penalized; settlement proceeds with available judgments | | Dispute window | Settlement becomes final and irreversible | | Claim deadline | Unclaimed funds forwarded to protocol treasury |