本文定义 task3/ 核心数据结构、类型定义和状态机 参考:TRUTH.md ADR-012
task3/ 系统包含以下核心数据模型:
┌──────────────────────────────────────────────────────────┐
│ 核心数据模型 │
├──────────────────────────────────────────────────────────┤
│ │
│ 1. Bounty(赏金实体) │
│ - 链上存储的赏金数据 │
│ - 包含状态、金额、参与者等信息 │
│ │
│ 2. TaskMetadata(任务元数据) │
│ - 任务的完整元信息 │
│ - 存储在数据层(GitHub Issue / IPFS 等) │
│ │
│ 3. BountyStatus(赏金状态枚举) │
│ - 定义赏金的 6 种状态 │
│ - 状态机转换规则 │
│ │
│ 4. Flow Params/Result(流程参数与返回值) │
│ - 5 个流程的输入输出数据结构 │
│ │
└──────────────────────────────────────────────────────────┘
定义位置: task3/bounty-operator/types.ts
export interface Bounty {
// ========== 基础信息 ==========
bountyId: string; // 赏金 ID(链上唯一标识)
taskId: string; // 任务 ID(如 "owner/repo#123" 或 UUID)
taskHash: string; // 任务内容哈希(用于幂等性检查)
// ========== 参与者 ==========
user: string; // 赏金发起人地址(requester)
worker: string | null; // 接单的 worker 地址(null 表示未接单)
// ========== 赏金信息 ==========
amount: string; // 赏金金额(字符串格式,避免精度问题)
asset: string; // 资产类型("USDT" / "APT" / "SUI" / "ETH" 等)
// ========== 状态与时间戳 ==========
status: BountyStatus; // 当前状态(见 2.2)
createdAt: number; // 创建时间(Unix 时间戳,秒)
acceptedAt: number | null; // 接受时间(null 表示未接受)
submittedAt: number | null; // 提交时间(worker 提交工作成果)
confirmedAt: number | null; // 确认时间(requester 确认工作成果)
claimedAt: number | null; // 领取时间(worker 领取赏金)
}字段说明:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
bountyId |
string | ✅ | 链上唯一标识,由合约生成 |
taskId |
string | ✅ | 任务 ID,格式依数据层而定 |
taskHash |
string | ✅ | SHA256(taskData),防止重复创建 |
user |
string | ✅ | 发起人的链上地址(requester) |
worker |
string | null | ❌ | 接单后才有值 |
amount |
string | ✅ | 使用字符串避免浮点数精度问题 |
asset |
string | ✅ | 资产标识符(代币名称或地址) |
status |
BountyStatus | ✅ | 当前状态(见 2.2) |
createdAt |
number | ✅ | 创建时的 Unix 时间戳 |
submittedAt |
number | null | ❌ | worker 提交工作成果的时间 |
confirmedAt |
number | null | ❌ | requester 确认工作成果的时间 |
claimedAt |
number | null | ❌ | worker 领取赏金的时间 |
定义位置: task3/bounty-operator/types.ts
export enum BountyStatus {
Open = 'Open', // 已发布,等待接单
Accepted = 'Accepted', // 已接单,worker 工作中
Submitted = 'Submitted', // worker 已提交工作成果
Confirmed = 'Confirmed', // requester 已确认,进入冷静期
Claimed = 'Claimed', // worker 已领取赏金
Cancelled = 'Cancelled' // user 已取消(仅 Open 状态可取消)
}状态说明:
| 状态 | 说明 | 可执行操作 | 下一状态 |
|---|---|---|---|
| Open | 赏金已创建,等待接单 | acceptBounty, cancelBounty | Accepted, Cancelled |
| Accepted | worker 已接单,开始工作 | submitBounty | Submitted |
| Submitted | worker 已提交工作成果 | confirmBounty | Confirmed |
| Confirmed | requester 已确认,可领取 | claimPayout | Claimed |
| Claimed | worker 已领取赏金 | - | 终态 |
| Cancelled | user 已取消赏金 | - | 终态 |
stateDiagram-v2
[*] --> Open: createBounty()
Open --> Accepted: acceptBounty()
Open --> Cancelled: cancelBounty()
Accepted --> Submitted: submitBounty()
Submitted --> Confirmed: confirmBounty()
Confirmed --> Claimed: claimBounty()
Claimed --> [*]
Cancelled --> [*]
note right of Open
user 可取消
end note
状态转换规则:
-
[*] → Open (
createBounty)- 触发者: User (requester)
- 前置条件: 无(初始状态)
- 链上操作: 锁定赏金金额到合约
- 后置条件:
- 赏金状态为
Open bountyId被创建createdAt被记录- 资金已锁定在合约中
- 赏金状态为
-
Open → Accepted (
acceptBounty)- 触发者: Worker(接受任务)
- 前置条件: 赏金状态为
Open - 链上操作: 将 worker 地址绑定到 bounty
- 后置条件:
- 赏金状态为
Accepted worker字段被设置acceptedAt被记录
- 赏金状态为
-
Accepted → Submitted (
submitBounty)- 触发者: Worker(提交工作成果)
- 前置条件:
- 赏金状态为
Accepted - 调用者必须是该 bounty 的 worker
- 赏金状态为
- 链上操作: 记录提交的 PR URL(或其他提交凭证)
- 后置条件:
- 赏金状态为
Submitted submittedAt被记录- 提交 URL 已上链
- 赏金状态为
-
Submitted → Confirmed (
confirmBounty)- 触发者: User (requester)(确认工作成果)
- 前置条件:
- 赏金状态为
Submitted - 调用者必须是该 bounty 的 user(原始发起人)
- 赏金状态为
- 链上操作: 确认工作成果
- 后置条件:
- 赏金状态为
Confirmed confirmedAt被记录
- 赏金状态为
-
Confirmed → Claimed (
claimBounty)- 触发者: Worker(领取赏金)
- 前置条件:
- 赏金状态为
Confirmed - 调用者必须是该 bounty 的 worker
- 赏金状态为
- 链上操作: 将锁定的资金转账给 worker
- 后置条件:
- 赏金状态为
Claimed claimedAt被记录- 资金已转账给 worker
- 赏金状态为
-
Open → Cancelled (
cancelBounty)- 触发者: User (requester)(取消赏金)
- 前置条件:
- 赏金状态为
Open(仅未接单的赏金可取消) - 调用者必须是该 bounty 的 user
- 赏金状态为
- 链上操作: 退还锁定的资金给 user
- 后置条件:
- 赏金状态为
Cancelled - 资金已退还给 user
- 赏金状态为
定义位置: task3/data-operator/types.ts
export interface TaskMetadata {
// ========== Schema 版本 ==========
schema: 'code3/v2'; // 元数据格式版本
// ========== 任务标识 ==========
taskId: string; // 任务 ID(如 "owner/repo#123" 或 IPFS CID)
taskHash: string; // 任务内容哈希(幂等性)
// ========== 链上信息 ==========
chain: {
name: string; // aptos / sui / ethereum
network: string; // testnet / mainnet
bountyId: string; // 关联的 bounty ID
contractAddress: string; // 合约地址
};
// ========== Workflow 信息 ==========
workflow: {
name: string; // spec-kit / observer / ...
version: string; // workflow 版本(如 "1.0.0")
adapter: string; // spec-kit-mcp-adapter / observer-adapter
};
// ========== 赏金信息 ==========
bounty: {
asset: string; // 资产类型
amount: string; // 赏金金额
confirmedAt: number | null; // requester 确认时间
};
// ========== 数据层信息 ==========
dataLayer: {
type: string; // github / ipfs / arweave / s3
url: string; // 数据层 URL(taskUrl)
};
}字段说明:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
schema |
string | ✅ | 固定为 "code3/v2",用于版本兼容性 |
taskId |
string | ✅ | 任务标识符,格式依数据层而定 |
taskHash |
string | ✅ | 任务内容的 SHA256 哈希 |
chain.name |
string | ✅ | 链名称(aptos/sui/ethereum) |
chain.network |
string | ✅ | 网络类型(testnet/mainnet) |
chain.bountyId |
string | ✅ | 关联的链上 bounty ID |
chain.contractAddress |
string | ✅ | 合约地址 |
workflow.name |
string | ✅ | workflow 名称 |
workflow.version |
string | ✅ | workflow 版本号 |
workflow.adapter |
string | ✅ | 使用的 adapter 名称 |
bounty.asset |
string | ✅ | 赏金资产类型 |
bounty.amount |
string | ✅ | 赏金金额 |
bounty.confirmedAt |
number | null | ❌ | 确认时间(确认后才有) |
dataLayer.type |
string | ✅ | 数据层类型 |
dataLayer.url |
string | ✅ | 任务数据的 URL(taskUrl) |
示例(GitHub + Aptos):
{
"schema": "code3/v2",
"taskId": "code3-team/repo#123",
"taskHash": "a3f8c9d2e1b4...",
"chain": {
"name": "aptos",
"network": "testnet",
"bountyId": "456",
"contractAddress": "0xabc123..."
},
"workflow": {
"name": "spec-kit",
"version": "1.0.0",
"adapter": "spec-kit-mcp-adapter"
},
"bounty": {
"asset": "USDT",
"amount": "100.00",
"confirmedAt": 1696550400
},
"dataLayer": {
"type": "github",
"url": "https://github.com/code3-team/repo/issues/123"
}
}定义位置: task3/orchestration/types.ts
export interface PublishFlowParams {
dataOperator: DataOperator; // 数据操作接口实例
bountyOperator: BountyOperator; // 链上操作接口实例
taskData: any; // 任务数据(workflow 特定格式)
metadata: TaskMetadata; // 任务元数据
amount: string; // 赏金金额
asset: string; // 资产类型
}
export interface PublishFlowResult {
taskUrl: string; // 任务 URL(GitHub Issue URL / IPFS CID 等)
bountyId: string; // 创建的 bounty ID
txHash: string | null; // 交易哈希(幂等时为 null)
isNew: boolean; // true=新创建, false=已存在(幂等)
}export interface AcceptFlowParams {
dataOperator: DataOperator; // 数据操作接口实例
bountyOperator: BountyOperator; // 链上操作接口实例
taskUrl: string; // 任务 URL
}
export interface AcceptFlowResult {
taskData: any; // 下载的任务数据(workflow 特定格式)
localPath: string; // 本地存储路径
bountyId: string; // 关联的 bounty ID
txHash: string; // 接受交易的哈希
}export interface SubmitFlowParams {
dataOperator: DataOperator; // 数据操作接口实例
bountyOperator: BountyOperator; // 链上操作接口实例
taskUrl: string; // 任务 URL
submissionData: any; // 提交数据(workflow 特定格式)
}
export interface SubmitFlowResult {
submissionUrl: string; // 提交 URL(GitHub PR URL / IPFS CID 等)
txHash: string; // 提交交易的哈希
}export interface ConfirmFlowParams {
bountyOperator: BountyOperator; // 链上操作接口实例
dataOperator: DataOperator; // 数据操作接口实例
taskUrl: string; // 任务 URL
}
export interface ConfirmFlowResult {
txHash: string; // 确认交易的哈希
coolingUntil: number; // 冷静期结束时间戳
}export interface ClaimFlowParams {
bountyOperator: BountyOperator; // 链上操作接口实例
dataOperator: DataOperator; // 数据操作接口实例
taskUrl: string; // 任务 URL
}
export interface ClaimFlowResult {
txHash: string; // 领取交易的哈希
amount: string; // 领取的赏金金额
asset: string; // 领取的资产类型
}export interface CreateBountyParams {
taskId: string; // 任务 ID
taskHash: string; // 任务内容哈希(幂等性)
amount: string; // 赏金金额
asset: string; // 资产类型
}
export interface CreateBountyResult {
bountyId: string; // 创建的 bounty ID
txHash: string; // 交易哈希
}export interface AcceptBountyParams {
bountyId: string; // Bounty ID
worker: string; // Worker 地址
}
export interface AcceptBountyResult {
txHash: string; // 交易哈希
acceptedAt: number; // 接受时间戳
}export interface SubmitBountyParams {
bountyId: string; // Bounty ID
submissionUrl: string; // 提交内容 URL
}
export interface SubmitBountyResult {
txHash: string; // 交易哈希
submittedAt: number; // 提交时间戳
}export interface ConfirmBountyParams {
bountyId: string; // Bounty ID
}
export interface ConfirmBountyResult {
txHash: string; // 交易哈希
}export interface ClaimPayoutParams {
bountyId: string; // Bounty ID
}
export interface ClaimPayoutResult {
txHash: string; // 交易哈希
claimedAt: number; // 领取时间戳
}export interface CancelBountyParams {
bountyId: string; // Bounty ID
}
export interface CancelBountyResult {
txHash: string; // 交易哈希
}export interface GetBountyParams {
bountyId: string; // Bounty ID
}
// 返回值:Bounty(见 Section 2.1)export interface GetBountyByTaskHashParams {
taskHash: string; // 任务内容哈希
}
export interface GetBountyByTaskHashResult {
found: boolean; // 是否找到
bountyId?: string; // Bounty ID(found=true 时有值)
}export interface ListBountiesParams {
offset?: number; // 偏移量(分页)
limit?: number; // 限制数量(分页)
}
export interface ListBountiesResult {
bounties: Bounty[]; // Bounty 列表
total: number; // 总数
}export interface GetBountiesByUserParams {
user: string; // User 地址(requester)
}
export interface GetBountiesByUserResult {
bounties: Bounty[]; // Bounty 列表
}export interface GetBountiesByWorkerParams {
worker: string; // Worker 地址
}
export interface GetBountiesByWorkerResult {
bounties: Bounty[]; // Bounty 列表
}export interface UploadTaskDataParams {
taskData: any; // 任务数据(workflow 特定格式)
metadata: TaskMetadata; // 任务元数据
}
export interface UploadTaskDataResult {
taskUrl: string; // 任务 URL(GitHub Issue URL / IPFS CID 等)
taskId: string; // 任务 ID
metadata: TaskMetadata; // 完整的任务元数据
}export interface DownloadTaskDataParams {
taskUrl: string; // 任务 URL
}
export interface DownloadTaskDataResult {
taskData: any; // 任务数据(workflow 特定格式)
localPath: string; // 本地存储路径
metadata: TaskMetadata; // 任务元数据
}export interface UploadSubmissionParams {
taskUrl: string; // 关联的任务 URL
submissionData: any; // 提交数据(workflow 特定格式)
metadata?: any; // 可选的额外元数据
}
export interface UploadSubmissionResult {
submissionUrl: string; // 提交 URL(GitHub PR URL / IPFS CID 等)
submissionId: string; // 提交 ID
metadata?: any; // 返回的元数据
}export interface GetTaskMetadataParams {
taskUrl: string; // 任务 URL
}
// 返回值:TaskMetadata(见 Section 3.1)export interface UpdateTaskMetadataParams {
taskUrl: string; // 任务 URL
metadata: Partial<TaskMetadata>; // 部分更新的元数据
}
export interface UpdateTaskMetadataResult {
success: boolean; // 是否成功
}目的: 防止重复创建相同的 bounty(如用户误操作、网络重试等)。
规则:
- 每个任务数据有唯一的
taskHash = SHA256(taskData) - 链上存储
taskHash → bountyId映射 - 创建 bounty 前,先查询
getBountyByTaskHash(taskHash) - 如果已存在,返回现有 bounty 信息(
isNew = false)
interface Bounty {
taskHash: string; // 任务内容的 SHA256 哈希(唯一标识)
}
interface PublishFlowResult {
isNew: boolean; // true=新创建, false=已存在(幂等)
txHash: string | null; // 幂等时为 null(无新交易)
}// 在 publishFlow 中实现幂等性
const taskHash = crypto.createHash('sha256').update(JSON.stringify(taskData)).digest('hex');
// 检查是否已存在
const existingBounty = await bountyOperator.getBountyByTaskHash({ taskHash });
if (existingBounty.found) {
// 已存在,返回现有 bounty
return {
taskUrl: metadata.dataLayer.url,
bountyId: existingBounty.bountyId,
txHash: null, // 无新交易
isNew: false // 幂等返回
};
}
// 不存在,创建新 bounty
const bountyResult = await bountyOperator.createBounty({ taskId, taskHash, amount, asset });- 接口定义: 02-interfaces.md
- ADR-012: TRUTH.md ADR-012
- 接口原始定义: interface.md