Abstract
ERC-8195 defines the Task Market Protocol (TMP), a standard interface for on-chain task
coordination supporting five procurement modes: Bounty, Claim, Pitch, Benchmark,
and Auction.
ERC-8195 is actor-agnostic: requesters and workers may be humans, autonomous AI agents, IoT
devices, or any combination thereof. A human may post a task for an AI agent to complete, an
AI agent may post a task for a human specialist, two agents may transact entirely without human
involvement, or two humans may use the protocol as a trustless escrow β the contract treats all
participants identically. This symmetry is grounded in ERC-8004, which provides a single
identity primitive shared by both human and machine actors.
ERC-8195 enables any frontend, aggregator, or autonomous agent to interact with any compliant task
market contract without implementation-specific knowledge. ERC-8195 is built on PGTR (ERC-8194),
which allows keyless actors to authorize task actions via on-chain payment receipts rather than
private-key signatures. ERC-8195 integrates ERC-8004 for actor-agnostic on-chain identity,
reputation, and automated benchmark validation.
Tasks are identified by bytes32 IDs generated deterministically by the contract using the
requesterβs address and a monotonic nonce, enabling backends to pre-compute task IDs before
transaction inclusion. Procurement modes are identified by bytes4 selectors computed from a
canonical string, making new modes detectable by tooling without contract upgrades.
Motivation
On-chain task markets have emerged independently across multiple ecosystems with incompatible
interfaces. The absence of a standard means:
- Fragmentation β Workers must track multiple incompatible contracts; aggregators must write
custom adapters. - Actor-specific designs β Existing markets are designed for either humans or agents, not
both. Human-facing markets require wallets and UIs; agent-facing markets require custom APIs.
Neither is natively composable with the other. - No keyless actor support β Existing designs require participants to hold private keys and
pay gas, excluding lightweight AI agents, IoT devices, and human users who prefer payment-only
authorization. - No automated evaluation β Benchmark-style tasks (prove you achieved metric X) require
trusted off-chain evaluators with no on-chain finality. - Missing portable identity β Reputation accrued on one market is not portable to another,
and there is no shared identity layer between human and machine participants.
ERC-8195 addresses all five gaps: a common interface, actor-agnostic design grounded in ERC-8004
identity, PGTR-based keyless authorization, ERC-8004 Validation Registry integration for
automated benchmarks, and ERC-8004 Reputation Registry for portable reputation across all
actor types.
Relationship to ERC-8183
ERC-8183 (Agentic Commerce, Feb 2026) establishes a minimal single-evaluator, single-flow job
coordination standard. ERC-8195 addresses a broader design space:
| Dimension | ERC-8183 | ERC-8195 |
|---|---|---|
| Actor model | Agent-focused | Actor-agnostic (human β agent, any combination) |
| Keyless actors | ERC-2771 (signature-based) | PGTR (payment-receipt-based) |
| Coordination modes | 1 linear flow | 5 modes |
| Trustless evaluation | Optional | Benchmark + ERC-8004 Validation Registry |
| ERC-8004 integration | Recommended | Normative (all 3 registries) |
| Staking | None | Claim mode stake/forfeit |
| Multi-forwarder | Single | mapping(address => bool) |
Every workflow ERC-8183 supports is expressible in ERC-8195 (Bounty mode, requester-as-evaluator).
The standards are complementary; minimal deployments may prefer ERC-8183, while multi-mode or
agent-native deployments should use ERC-8195.
Relationship to ERC-8001
ERC-8001 (if finalized) defines a coordination envelope and bounded delegation layer that could
complement ERC-8195βs lifecycle interface. ERC-8195 does not take a normative dependency on
ERC-8001: the coordination gaps ERC-8001 addresses (mode-specific negotiation artefacts, bounded
authority) are covered within ERC-8195 by Appendix Aβs canonical payload schemas and by PGTRβs
receipt-scoped authorization model respectively. Implementations MAY use ERC-8001-compatible
coordination payloads; this is not required for ERC-8195 compliance.
Specification
The key words βMUSTβ, βMUST NOTβ, βREQUIREDβ, βSHALLβ, βSHOULDβ, βSHOULD NOTβ, βRECOMMENDEDβ,
βMAYβ, and βOPTIONALβ are interpreted as described in RFC 2119.
Part I: Core Interface (ITMP)
Mode Constants
ERC-8195 modes are identified by bytes4 constants computed as the first 4 bytes of the Keccak256
hash of the canonical mode name string. Using selectors rather than enum values allows new modes
to be deployed and detected by tooling without modifying existing contracts.
bytes4 constant TMP_BOUNTY = bytes4(keccak256("TMP.mode.bounty"));
bytes4 constant TMP_CLAIM = bytes4(keccak256("TMP.mode.claim"));
bytes4 constant TMP_PITCH = bytes4(keccak256("TMP.mode.pitch"));
bytes4 constant TMP_BENCHMARK = bytes4(keccak256("TMP.mode.benchmark"));
bytes4 constant TMP_AUCTION = bytes4(keccak256("TMP.mode.auction"));
See Appendix B for exact 32-bit values.
Task Status
enum TaskStatus {
Open, // Task is accepting work
Claimed, // A worker has locked the task (Claim / Auction modes)
WorkerSelected, // Requester has selected a worker (Pitch mode)
PendingApproval, // Work submitted, awaiting requester acceptance (Bounty / Benchmark modes)
Accepted, // Work accepted; payment released to worker
Expired, // Task expired without acceptance; reward refunded to requester
Cancelled // Task cancelled by requester before work began
}
Disputed is intentionally absent from the core enum. Dispute resolution is an optional extension
defined in ITMPDispute. Core protocol implementations are not required to support disputes.
Data Structures
/// @notice Canonical task representation returned by getTask().
struct Task {
bytes32 id;
address requester;
uint256 reward;
uint256 expiryTime;
bytes4 mode;
TaskStatus status;
address worker;
bytes32 deliverable;
bytes32 contentHash;
string contentURI;
}
/// @notice Cumulative statistics for a worker address.
struct WorkerStats {
uint256 tasksCompleted;
uint256 tasksAttempted;
uint256 totalEarned;
uint256 avgRating;
uint256 ratingCount;
}
ITMP Interface
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "./IPGTRForwarder.sol";
/// @title ITMP β Task Market Protocol Core Interface
/// @notice An ERC-8195-compliant contract MUST implement all functions and events in this interface
/// and MUST return true from supportsInterface(type(ITMP).interfaceId).
interface ITMP is IERC165 {
// βββ Events ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
/// @notice Emitted when a new task is created.
event TaskCreated(
bytes32 indexed taskId,
address indexed requester,
uint256 reward,
bytes4 indexed mode,
uint256 expiryTime
);
/// @notice Emitted when a worker submits a deliverable hash.
event TaskSubmitted(
bytes32 indexed taskId,
address indexed worker,
bytes32 deliverable
);
/// @notice Emitted when the requester accepts a submission and payment is released.
event TaskCompleted(
bytes32 indexed taskId,
address indexed worker,
uint256 reward
);
/// @notice Emitted when a task expires and reward is returned to the requester.
event TaskExpired(bytes32 indexed taskId, address indexed requester, uint256 reward);
/// @notice Emitted when a requester rates a completed task.
event TaskRated(
bytes32 indexed taskId,
address indexed worker,
uint8 rating,
uint256 raterAgentId // ERC-8004 agent ID of the requester (0 if unregistered)
);
// βββ Task Lifecycle βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
/// @notice Create a new task and escrow the reward.
function createTask(
address requester,
uint256 reward,
uint256 duration,
bytes4 mode,
uint256 pitchDeadline,
uint256 bidDeadline
) external returns (bytes32 taskId);
/// @notice Record a deliverable hash submitted by a worker.
function submitWork(bytes32 taskId, address worker, bytes32 deliverable) external;
/// @notice Accept a worker's submission and release the escrowed reward.
function acceptSubmission(bytes32 taskId, address requester, address worker) external;
/// @notice Rate a completed task and record feedback in the ERC-8004 Reputation Registry.
function rateTask(
bytes32 taskId,
uint8 rating,
uint256 workerAgentId,
uint256 raterAgentId,
string calldata feedbackURI,
bytes32 feedbackHash
) external;
/// @notice Refund the escrowed reward to the requester after expiry.
function refundExpired(bytes32 taskId) external;
// βββ View Functions βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
/// @notice Returns full task information.
function getTask(bytes32 taskId) external view returns (Task memory);
/// @notice Returns cumulative statistics for a worker address.
function getWorkerStats(address worker) external view returns (WorkerStats memory);
/// @notice Returns the current requester nonce used for task ID generation.
function requesterNonce(address requester) external view returns (uint256);
/// @notice Returns true if addr is a trusted PGTR forwarder.
function isTrustedForwarder(address addr) external view returns (bool);
}
Part II: Mode State Machines (Normative)
The following state diagrams define all valid state transitions for each mode.
* denotes an off-chain action relayed by a PGTR forwarder; submitWork* records the deliverable
hash on-chain but does NOT change status in Claim/Pitch/Auction modes.
Bounty Mode
Any worker may submit. First accepted submission wins.
Open
--[submitWork]--> PendingApproval
--[expire]------> Expired
PendingApproval
--[acceptSubmission]--> Accepted
--[expire]-----------> Expired (deliverable retained)
Claim Mode
Workers lock the task by staking. Stake is forfeited on failure.
Open
--[claimTask*]---> Claimed
--[expire]-------> Expired
Claimed
--[submitWork*]---> Claimed (deliverable hash recorded; status unchanged)
--[acceptSubmission]--> Accepted
--[forfeitClaim*]---> Open (stake forfeited; task re-opens)
--[expire]---------> Expired (stake returned to worker if configured)
Pitch Mode
Requester selects a worker from pitches before work begins.
Open
--[submitPitch*]----> Open (pitch recorded off-chain; status unchanged)
--[selectWorker]----> WorkerSelected
--[expire]----------> Expired
WorkerSelected
--[submitWork*]----> WorkerSelected (deliverable hash recorded; status unchanged)
--[acceptSubmission]--> Accepted
--[expire]----------> Expired
Benchmark Mode
Work is validated automatically by the ERC-8004 Validation Registry.
Open
--[submitWork]--> PendingApproval
--[expire]------> Expired
PendingApproval
--[acceptSubmission (via Validation Registry)]--> Accepted
--[expire]-----> Expired (deliverable retained)
In Benchmark mode, evaluatorFor(taskId) returns the ERC-8004 Validation Registry address.
The forwarder MUST submit the proof to the Validation Registry off-chain; the Registry calls
acceptSubmission on the ERC-8195 contract if the proof is valid.
Auction Mode
Workers submit sealed bids; lowest bidder wins the right to do the work.
Open
--[submitBid*]-------> Open (bid recorded; status unchanged)
--[selectLowestBidder]--> Claimed (winning bidder locked)
--[expire]-----------> Expired
Claimed (winner locked)
--[submitWork*]----> Claimed (deliverable hash recorded; status unchanged)
--[acceptSubmission]--> Accepted
--[expire]----------> Expired
Note: selectLowestBidder performs an O(n) scan over all bids. Implementations SHOULD
maintain a running minimum during submitBid to enable O(1) selection.
Part III: Task ID Generation
Task IDs MUST be generated by the contract as:
taskId = keccak256(abi.encode(
block.chainid,
address(this),
requester,
requesterNonce[requester]++
));
This scheme guarantees:
- Uniqueness β chain ID + contract address + requester + monotonic nonce cannot collide.
- Pre-computability β backends can predict the ID by reading
requesterNonce[requester]
before submitting the transaction. - No off-chain randomness β no server-side random bytes required.
- Cross-chain disambiguation β the chain ID prevents the same ID appearing on two chains.
Part IV: Deliverable Anchoring
The submitWork function MUST accept a bytes32 deliverable parameter and store it on-chain
as part of the task record. The deliverable hash provides a tamper-evident anchor for:
- IPFS CIDs β keccak256 of the CID bytes
- File content β keccak256 of the raw file
- ZK commitments β commitment value from a zero-knowledge proof
- Merkle roots β root of a structured proof tree
The deliverable field MUST be zero for tasks where no submission has been recorded.
Once set, the deliverable field MUST NOT be overwritten by a subsequent submitWork call.
Part V: ERC-8004 Integration (Normative)
ERC-8004 is the actor-agnostic identity layer for ERC-8195. Both human and machine participants
(requesters and workers) are represented as ERC-8004 actors. This shared identity primitive
enables human-to-agent, agent-to-human, agent-to-agent, and human-to-human task interactions
to be treated uniformly by the protocol and by reputation indexers.
ERC-8195 contracts that support reputation MUST integrate with all three ERC-8004 registries:
Identity Registry
Requesters and workers are ERC-8004 actors β human or machine. The workerAgentId parameter
in rateTask MUST correspond to a valid actor ID in the ERC-8004 Identity Registry. Any
participant that registers an ERC-8004 identity (human or AI agent) participates in the same
reputation graph.
Reputation Registry
When rateTask is called, the contract MUST call:
IReputationRegistry.giveFeedback(
workerAgentId,
int128(rating),
0, // valueDecimals
"tmp.task.rating", // tag1 β canonical ERC-8195 tag
_modeName(task.mode), // tag2 β e.g., "tmp.mode.bounty"
feedbackURI,
feedbackHash
);
The canonical tag "tmp.task.rating" MUST be used for tag1. Indexers and reputation aggregators
SHOULD filter on this tag to identify ERC-8195-sourced feedback. The mode name in tag2 allows
mode-specific reputation segmentation (e.g., separate scores for benchmark vs. bounty work).
The raterAgentId parameter MUST be emitted in TaskRated so indexers can attribute feedback
to a specific ERC-8004 actor. IReputationRegistry.giveFeedback records the workerβs reputation;
rater identity is anchored on-chain via the event. Implementations MUST pass 0 for raterAgentId
when the requester has not registered an ERC-8004 identity.
Validation Registry (Benchmark Mode Only)
In Benchmark mode, the forwarder MUST:
- Submit the workerβs proof to the ERC-8004 Validation Registry.
- The Validation Registry evaluates the proof against the taskβs
metricTarget. - If valid, the Registryβs callback triggers
acceptSubmissionon the ERC-8195 contract.
The ERC-8195 contract MUST NOT accept acceptSubmission calls from arbitrary addresses in Benchmark
mode β only from the Validation Registry (returned by evaluatorFor(taskId)).
Part VI: Optional Extension Interfaces
ERC-8195 implementations MAY implement the following optional extension interfaces. Callers SHOULD
check for these via ERC-165 before calling extension functions.
ITMPMode
interface ITMPMode is IERC165 {
/// @notice Returns the address responsible for evaluating task completion.
/// Bounty/Claim: returns requester
/// Benchmark: returns ERC-8004 Validation Registry
/// Pitch/Auction: returns requester (or designated arbitrator)
function evaluatorFor(bytes32 taskId) external view returns (address evaluator);
}
ITMPFees
interface ITMPFees is IERC165 {
/// @notice Platform fee in basis points deducted from reward on task completion.
function defaultFeeBps() external view returns (uint16);
/// @notice Address that receives platform fees.
function feeRecipient() external view returns (address);
/// @notice Cumulative fees collected since deployment.
function totalFeesCollected() external view returns (uint256);
/// @notice Effective fee amount that will be deducted for a given reward.
function feeForTask(uint256 reward) external view returns (uint256);
}
ITMPReputation
interface ITMPReputation is IERC165 {
/// @notice The ERC-8004 Reputation Registry used for feedback submission.
function reputationRegistry() external view returns (address);
event ReputationRegistryUpdated(address indexed registry);
}
ITMPDispute
interface ITMPDispute is IERC165 {
enum DisputeStatus { None, Open, Resolved }
/// @notice Returns dispute status for a task.
function disputeStatus(bytes32 taskId) external view returns (DisputeStatus);
/// @notice Returns the arbitrator for a task (zero if no dispute).
function arbitratorFor(bytes32 taskId) external view returns (address);
/// @notice Open a dispute for a task in PendingApproval or Accepted state.
function openDispute(bytes32 taskId, address initiator, string calldata reason) external;
/// @notice Resolve a dispute. Only callable by arbitratorFor(taskId).
/// workerShare + requesterShare MUST equal 100.
function resolveDispute(bytes32 taskId, uint8 workerShare, uint8 requesterShare) external;
event DisputeOpened(bytes32 indexed taskId, address indexed initiator);
event DisputeResolved(bytes32 indexed taskId, uint8 workerShare, uint8 requesterShare);
}
Normative requirement: ITMPDispute implementations MUST NOT interfere with refundExpired.
A task that has reached its expiryTime MUST be refundable even if a dispute is open. This
invariant protects requesters from griefing via spurious dispute opens.
Part VII: Fund Recovery Invariant (Normative)
refundExpired MUST:
- Be callable by any address (permissionless).
- Succeed whenever
block.timestamp > task.expiryTimeandtask.statusisOpen,Claimed,
orWorkerSelected. - NOT be blocked by any hook, extension contract, or dispute state.
- Transfer the full escrowed reward to
task.requester. - Emit
TaskExpired.
This invariant MUST hold unconditionally. Implementations MUST verify it in their test suite.
Part VIII: Indexer Event Requirements
All state transitions MUST emit events with sufficient data to reconstruct full task history
from a stateless event scan. Specifically:
TaskCreatedMUST include all parameters needed to reconstruct the initial task state.TaskSubmittedMUST include the deliverable hash.TaskCompletedMUST include worker address and reward amount.TaskExpiredMUST include requester address and refunded reward amount.TaskRatedMUST be emitted byrateTaskand MUST includeworker,rating, andraterAgentId.ForwarderUpdated(address indexed forwarder, bool trusted)MUST be emitted on every
addForwarderandremoveForwardercall.
Rationale
bytes4 mode selectors vs. enum
An enum encodes modes as consecutive integers. Adding a new mode requires modifying the contract
(breaking existing ABIs). bytes4 selectors are computed from canonical strings, so:
- New modes have globally unique identifiers derivable without reading contract storage.
- The selector itself carries semantic meaning (readable as a string).
- Aggregators can detect supported modes via
supportsInterfacepattern extensions without
on-chain enumeration.
Contract-generated task IDs
Client-supplied task IDs (random bytes32) create a race condition: two clients may submit the same
ID, and the second will fail on-chain after paying gas. They also require the client to manage
entropy, which is non-trivial for lightweight agents. Contract-generated IDs using a monotonic
nonce eliminate both problems while remaining pre-computable.
submitWork as a separate step
Separating submitWork from acceptSubmission provides an on-chain audit trail:
- The deliverable hash is anchored before the requester evaluates it.
- ZK proofs, IPFS CIDs, and other content-addressed references are immutably recorded.
- Disputes have an on-chain record of exactly what was submitted and when.
Off-chain submission in Claim/Pitch/Auction modes
In Claim, Pitch, and Auction modes, the worker is already locked to the task (no competitive
race). submitWork in these modes records the deliverable hash on-chain but does not change
status, because the relevant gate (acceptance) is an explicit requester action. Emitting
TaskSubmitted regardless of mode provides consistent indexer behavior.
PGTR over ERC-2771
See ERC-8194 Β§Relationship to ERC-2771.
Backwards Compatibility
This ERC introduces a new interface. Existing task market contracts are unaffected unless they
choose to implement ITMP. Contracts may add supportsInterface(type(ITMP).interfaceId) as an
additive upgrade, provided the underlying function signatures match the ITMP interface.
Reference Implementation
See daydreamsai/taskmarket-contracts for the reference implementation (src/TaskMarket.sol) and compliance test suite (test/ITMP.t.sol). The test suite covers all 5 mode state machines, ERC-165 interface detection, deliverable anchoring, the fund recovery invariant, and multi-forwarder add/remove.
Appendix A: Canonical Task Metadata JSON Schema
ERC-8195 tasks MAY reference extended metadata at contentURI. The following JSON schema defines the
canonical format. Indexers and frontends SHOULD use this schema for interoperability.
{
"$schema": "https://json-schema.org/draft/2020-12",
"title": "ERC-8195 Task Metadata",
"type": "object",
"required": ["title", "description", "mode", "reward"],
"properties": {
"title": {
"type": "string",
"description": "Short human-readable task title"
},
"description": {
"type": "string",
"description": "Full task description"
},
"mode": {
"type": "string",
"enum": ["bounty", "claim", "pitch", "benchmark", "auction"],
"description": "Procurement mode"
},
"reward": {
"type": "string",
"description": "Reward amount in USDC base units (string to avoid precision loss)"
},
"tags": {
"type": "array",
"items": { "type": "string" },
"description": "Searchable tags"
},
"benchmark": {
"type": "object",
"description": "Present only for benchmark mode tasks",
"properties": {
"metricDescription": { "type": "string" },
"metricTarget": { "type": "string" },
"validatorAddress": {
"type": "string",
"description": "ERC-8004 Validation Registry address"
},
"proofType": {
"type": "string",
"description": "Expected proof format (e.g., 'zk-snark', 'benchmark-result-json')"
}
},
"required": ["metricDescription", "metricTarget", "validatorAddress", "proofType"]
},
"auction": {
"type": "object",
"description": "Present only for auction mode tasks",
"properties": {
"auctionType": {
"type": "string",
"enum": ["dutch", "english", "reverse_dutch", "reverse_english"]
},
"maxPrice": { "type": "string" },
"floorPrice": { "type": "string" },
"startPrice": { "type": "string" },
"bidDeadline": {
"type": "integer",
"description": "Unix timestamp when bidding closes"
}
}
},
"createdAt": {
"type": "integer",
"description": "Unix timestamp of task creation"
},
"chainId": {
"type": "integer",
"description": "EVM chain ID where the task contract is deployed"
},
"contractAddress": {
"type": "string",
"description": "ERC-8195 contract address (checksummed)"
}
}
}
Appendix A.2: Benchmark Proof Envelope
Implementations MAY use the following envelope format when submitting a benchmark proof to an
external Validation Registry. No normative requirement to submit to a Validation Registry is
imposed by this ERC; the schema is provided for interoperability among implementations that
choose to integrate one.
{
"$schema": "https://json-schema.org/draft/2020-12",
"title": "ERC-8195 Benchmark Proof Envelope",
"type": "object",
"required": ["taskId", "contractAddress", "chainId", "worker", "deliverable", "metricTarget", "proofType", "proof", "submittedAt"],
"properties": {
"taskId": { "type": "string" },
"contractAddress": { "type": "string" },
"chainId": { "type": "integer" },
"worker": { "type": "string" },
"deliverable": { "type": "string" },
"metricTarget": { "type": "string" },
"proofType": { "type": "string", "examples": ["zk-snark", "benchmark-result-json", "merkle-proof"] },
"proof": { "type": "object" },
"submittedAt": { "type": "integer" }
}
}
Appendix A.3: Mode Coordination Payload Schemas
The following schemas define canonical off-chain payloads for mode-specific coordination actions.
Forwarder backends SHOULD use these schemas for interoperability. These payloads are transmitted
off-chain; only the resulting on-chain state (deliverable hash, bid record, claim record) is
normative.
Pitch Payload (submitted when submitPitch* is relayed):
{
"title": "ERC-8195 Pitch Payload",
"type": "object",
"required": ["taskId", "worker", "pitchText", "submittedAt"],
"properties": {
"taskId": { "type": "string" },
"worker": { "type": "string" },
"pitchText": { "type": "string" },
"attachmentURI": { "type": "string" },
"attachmentHash": { "type": "string" },
"submittedAt": { "type": "integer" }
}
}
Bid Payload (submitted when submitBid* is relayed):
{
"title": "ERC-8195 Bid Payload",
"type": "object",
"required": ["taskId", "worker", "bidAmount", "submittedAt"],
"properties": {
"taskId": { "type": "string" },
"worker": { "type": "string" },
"bidAmount": { "type": "string" },
"commitmentHash": { "type": "string" },
"submittedAt": { "type": "integer" }
}
}
Claim Payload (submitted when claimTask* is relayed):
{
"title": "ERC-8195 Claim Payload",
"type": "object",
"required": ["taskId", "worker", "stakeAmount", "submittedAt"],
"properties": {
"taskId": { "type": "string" },
"worker": { "type": "string" },
"stakeAmount": { "type": "string" },
"submittedAt": { "type": "integer" }
}
}
Appendix B: Mode Selector Values
The canonical bytes4 mode selectors, computed as bytes4(keccak256("<string>")):
| Mode | Input String | bytes4 Value |
|---|---|---|
| Bounty | "TMP.mode.bounty" |
bytes4(keccak256("TMP.mode.bounty")) |
| Claim | "TMP.mode.claim" |
bytes4(keccak256("TMP.mode.claim")) |
| Pitch | "TMP.mode.pitch" |
bytes4(keccak256("TMP.mode.pitch")) |
| Benchmark | "TMP.mode.benchmark" |
bytes4(keccak256("TMP.mode.benchmark")) |
| Auction | "TMP.mode.auction" |
bytes4(keccak256("TMP.mode.auction")) |
Appendix C: ERC-165 Interface IDs
| Interface | Solidity expression |
|---|---|
IERC165 |
0x01ffc9a7 (standard) |
| ITMP | type(ITMP).interfaceId |
| IPGTRForwarder | type(IPGTRForwarder).interfaceId |
| ITMPMode | type(ITMPMode).interfaceId |
| ITMPFees | type(ITMPFees).interfaceId |
| ITMPReputation | type(ITMPReputation).interfaceId |
| ITMPDispute | type(ITMPDispute).interfaceId |
All non-standard IDs are computed at compile time by Solidity as the XOR of function selectors.
To verify: cast interface <address> | grep interfaceId after deploying the reference implementation.
Security Considerations
-
Payment atomicity β All payment operations (escrow on create, release on accept, refund on
expire) MUST be atomic. Partial state updates with external token calls MUST use
ReentrancyGuardor equivalent. -
Forwarder trust β The
trustedForwardersmapping is a privileged set. Adding a malicious
forwarder allows arbitrary task creation and work acceptance on behalf of any requester.
addForwarderMUST be protected byonlyOwneror equivalent governance. -
Staking collateral β In Claim mode, stake amounts SHOULD be set high enough to make
griefing (claim-and-abandon) economically unattractive.stakeBpsis a percentage of reward;
implementations SHOULD enforce a minimum absolute stake. -
Benchmark oracle trust β The Validation Registry in Benchmark mode is trusted to evaluate
proofs fairly. Requesters SHOULD use audited, reputable registry implementations. The ERC-8195
contract SHOULD emit the registry address inTaskCreatedso requesters can verify it
before posting a task. -
Auction gas β
selectLowestBidderis O(1) when implementations maintain a running minimum
during bid submission. Implementations that do not MUST document the gas risk in the frontend. -
Expiry clock β
expiryTimeis set toblock.timestamp + durationat task creation.
Block timestamps are manipulable by validators within ~15 seconds. Tasks with very short
durations (< 60 seconds) SHOULD NOT be used in adversarial contexts. -
Re-rating β Implementations MUST prevent multiple
rateTaskcalls for the same
(taskId, requester) pair to avoid reputation inflation.
Copyright
Copyright and related rights waived via CC0.