@blindmarket/sdk 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/README.md +242 -29
  2. package/dist/chain/BlindEscrowClient.d.ts +2 -0
  3. package/dist/chain/BlindEscrowClient.js +19 -7
  4. package/dist/chain/BlindReputationClient.d.ts +3 -0
  5. package/dist/chain/BlindReputationClient.js +3 -1
  6. package/dist/chain/ChainClient.d.ts +6 -3
  7. package/dist/chain/ChainClient.js +6 -1
  8. package/dist/chain/IBlindMarketChain.d.ts +74 -0
  9. package/dist/chain/IBlindMarketChain.js +1 -0
  10. package/dist/chain/TaskRegistryClient.d.ts +2 -1
  11. package/dist/chain/TaskRegistryClient.js +15 -7
  12. package/dist/chain/createChainAdapter.d.ts +25 -0
  13. package/dist/chain/createChainAdapter.js +24 -0
  14. package/dist/chain/domain-types.d.ts +77 -0
  15. package/dist/chain/domain-types.js +1 -0
  16. package/dist/chain/evm/EVMChainAdapter.d.ts +56 -0
  17. package/dist/chain/evm/EVMChainAdapter.js +161 -0
  18. package/dist/chain/evm/index.d.ts +1 -0
  19. package/dist/chain/evm/index.js +1 -0
  20. package/dist/chain/index.d.ts +4 -0
  21. package/dist/chain/index.js +5 -0
  22. package/dist/crypto/constants.js +1 -1
  23. package/dist/errors/{BlindBountyError.d.ts → BlindMarketError.d.ts} +1 -1
  24. package/dist/errors/{BlindBountyError.js → BlindMarketError.js} +1 -1
  25. package/dist/errors/index.d.ts +1 -1
  26. package/dist/errors/index.js +1 -1
  27. package/dist/errors/subclasses.d.ts +9 -9
  28. package/dist/errors/subclasses.js +9 -9
  29. package/dist/executor/WorkerRuntime.d.ts +113 -0
  30. package/dist/executor/WorkerRuntime.js +248 -0
  31. package/dist/executor/index.d.ts +1 -0
  32. package/dist/executor/index.js +1 -0
  33. package/dist/index.d.ts +292 -22
  34. package/dist/index.js +413 -23
  35. package/dist/keystore/InMemoryKeyStore.js +2 -2
  36. package/dist/network/presets.d.ts +33 -5
  37. package/dist/network/presets.js +35 -8
  38. package/dist/network/resolve.d.ts +12 -3
  39. package/dist/network/resolve.js +15 -7
  40. package/dist/network/types.d.ts +3 -16
  41. package/dist/signer/EthersSigner.js +1 -1
  42. package/dist/storage/index.d.ts +0 -1
  43. package/dist/storage/index.js +1 -1
  44. package/dist/tools/adapters.d.ts +99 -0
  45. package/dist/tools/adapters.js +129 -0
  46. package/dist/tools/helpers.d.ts +9 -0
  47. package/dist/tools/helpers.js +169 -0
  48. package/dist/tools/index.d.ts +36 -0
  49. package/dist/tools/index.js +32 -0
  50. package/dist/tools/types.d.ts +44 -0
  51. package/dist/tools/types.js +1 -0
  52. package/dist/types.d.ts +202 -1
  53. package/dist/types.js +24 -1
  54. package/package.json +13 -2
  55. package/src/chain/BlindEscrowClient.ts +20 -6
  56. package/src/chain/BlindReputationClient.ts +6 -1
  57. package/src/chain/ChainClient.ts +9 -3
  58. package/src/chain/IBlindMarketChain.ts +109 -0
  59. package/src/chain/TaskRegistryClient.ts +17 -8
  60. package/src/chain/createChainAdapter.ts +40 -0
  61. package/src/chain/domain-types.ts +92 -0
  62. package/src/chain/evm/EVMChainAdapter.ts +212 -0
  63. package/src/chain/evm/index.ts +1 -0
  64. package/src/chain/index.ts +6 -0
  65. package/src/executor/WorkerRuntime.ts +338 -0
  66. package/src/executor/index.ts +8 -0
  67. package/src/index.ts +546 -36
  68. package/src/network/presets.ts +47 -8
  69. package/src/network/resolve.ts +20 -8
  70. package/src/network/types.ts +18 -16
  71. package/src/signer/index.ts +1 -1
  72. package/src/storage/index.ts +1 -1
  73. package/src/tools/adapters.ts +177 -0
  74. package/src/tools/helpers.ts +199 -0
  75. package/src/tools/index.ts +59 -0
  76. package/src/tools/types.ts +47 -0
  77. package/src/types.ts +222 -1
  78. package/tsconfig.json +2 -1
  79. package/dist/BlindEscrowClient-CyPuKMge.d.cts +0 -54
  80. package/dist/BlindEscrowClient-R7iGpE-n.d.ts +0 -54
  81. package/dist/KeyStore-Be_SSpCt.d.cts +0 -21
  82. package/dist/KeyStore-k1JgYPJY.d.ts +0 -21
  83. package/dist/Signer-BnqH_qew.d.cts +0 -38
  84. package/dist/Signer-LColE0Uo.d.ts +0 -38
  85. package/dist/Storage-4QOrh7rm.d.ts +0 -17
  86. package/dist/Storage-Cf4IJRMk.d.cts +0 -17
  87. package/dist/TaskRegistryClient-Ch6lYqM_.d.ts +0 -24
  88. package/dist/TaskRegistryClient-CrQjddDc.d.cts +0 -24
  89. package/dist/aes-J-7HrHze.d.cts +0 -17
  90. package/dist/aes-J-7HrHze.d.ts +0 -17
  91. package/dist/agent/index.cjs +0 -425
  92. package/dist/agent/index.cjs.map +0 -1
  93. package/dist/agent/index.d.cts +0 -63
  94. package/dist/agent/index.js.map +0 -1
  95. package/dist/api/index.cjs +0 -4
  96. package/dist/api/index.cjs.map +0 -1
  97. package/dist/api/index.d.cts +0 -2
  98. package/dist/api/index.js.map +0 -1
  99. package/dist/chain/index.cjs +0 -2484
  100. package/dist/chain/index.cjs.map +0 -1
  101. package/dist/chain/index.d.cts +0 -2305
  102. package/dist/chain/index.js.map +0 -1
  103. package/dist/compute/index.cjs +0 -4
  104. package/dist/compute/index.cjs.map +0 -1
  105. package/dist/compute/index.d.cts +0 -2
  106. package/dist/compute/index.js.map +0 -1
  107. package/dist/crypto/index.cjs +0 -424
  108. package/dist/crypto/index.cjs.map +0 -1
  109. package/dist/crypto/index.d.cts +0 -74
  110. package/dist/crypto/index.js.map +0 -1
  111. package/dist/errors/index.cjs +0 -136
  112. package/dist/errors/index.cjs.map +0 -1
  113. package/dist/errors/index.d.cts +0 -60
  114. package/dist/errors/index.js.map +0 -1
  115. package/dist/events/index.cjs +0 -41
  116. package/dist/events/index.cjs.map +0 -1
  117. package/dist/events/index.d.cts +0 -61
  118. package/dist/events/index.js.map +0 -1
  119. package/dist/index.cjs +0 -4
  120. package/dist/index.cjs.map +0 -1
  121. package/dist/index.d.cts +0 -2
  122. package/dist/index.js.map +0 -1
  123. package/dist/keystore/index.cjs +0 -335
  124. package/dist/keystore/index.cjs.map +0 -1
  125. package/dist/keystore/index.d.cts +0 -23
  126. package/dist/keystore/index.js.map +0 -1
  127. package/dist/network/index.cjs +0 -74
  128. package/dist/network/index.cjs.map +0 -1
  129. package/dist/network/index.d.cts +0 -36
  130. package/dist/network/index.js.map +0 -1
  131. package/dist/signer/index.cjs +0 -121
  132. package/dist/signer/index.cjs.map +0 -1
  133. package/dist/signer/index.d.cts +0 -40
  134. package/dist/signer/index.js.map +0 -1
  135. package/dist/storage/ZgStorage.d.ts +0 -24
  136. package/dist/storage/ZgStorage.js +0 -102
  137. package/dist/storage/index.cjs +0 -221
  138. package/dist/storage/index.cjs.map +0 -1
  139. package/dist/storage/index.d.cts +0 -44
  140. package/dist/storage/index.js.map +0 -1
  141. package/dist/testing/index.cjs +0 -4
  142. package/dist/testing/index.cjs.map +0 -1
  143. package/dist/testing/index.d.cts +0 -2
  144. package/dist/testing/index.js.map +0 -1
  145. package/dist/types-BOG5Ub1z.d.cts +0 -31
  146. package/dist/types-BOG5Ub1z.d.ts +0 -31
  147. package/dist/types-V7_ZmUb-.d.cts +0 -19
  148. package/dist/types-hAsITUQ7.d.ts +0 -19
  149. package/dist/verifier/index.cjs +0 -4
  150. package/dist/verifier/index.cjs.map +0 -1
  151. package/dist/verifier/index.d.cts +0 -2
  152. package/dist/verifier/index.js.map +0 -1
  153. package/dist/worker/index.cjs +0 -382
  154. package/dist/worker/index.cjs.map +0 -1
  155. package/dist/worker/index.d.cts +0 -58
  156. package/dist/worker/index.js.map +0 -1
package/dist/types.d.ts CHANGED
@@ -12,7 +12,7 @@ export interface Reward {
12
12
  token: Address | TokenSymbol;
13
13
  amount: bigint;
14
14
  }
15
- export type TaskStatus = 'funded' | 'assigned' | 'submitted' | 'verified' | 'completed' | 'cancelled';
15
+ export type TaskStatus = 'funded' | 'assigned' | 'submitted' | 'verified' | 'completed' | 'cancelled' | 'disputed';
16
16
  export interface TaskMetadata {
17
17
  category: string;
18
18
  locationZone: string;
@@ -56,3 +56,204 @@ export interface TxReceiptLike {
56
56
  gasUsed: bigint;
57
57
  }
58
58
  export type Awaitable<T> = T | Promise<T>;
59
+ export interface HealthStatus {
60
+ status: string;
61
+ timestamp: string;
62
+ }
63
+ export interface PlatformStats {
64
+ openTasks: number;
65
+ activeAgents: number;
66
+ activeValidators: number;
67
+ totalAgents: number;
68
+ registeredUsers: number;
69
+ completedTasks: number;
70
+ activeWorkers: number;
71
+ }
72
+ export interface OpenTask {
73
+ id: number;
74
+ agent: Address;
75
+ worker?: Address;
76
+ amount: string;
77
+ token: Address;
78
+ category: string;
79
+ locationZone: string;
80
+ deadline: number;
81
+ status: number;
82
+ taskHash?: Hex;
83
+ }
84
+ export interface CreateTaskTx {
85
+ unsignedTx: {
86
+ to: Address;
87
+ data: Hex;
88
+ value?: string;
89
+ };
90
+ }
91
+ export interface TaskDetail extends OpenTask {
92
+ metadata?: Record<string, unknown>;
93
+ a2aState?: A2ATaskState;
94
+ }
95
+ export interface A2ATaskState {
96
+ taskId: string;
97
+ status: string;
98
+ executorAddress?: string;
99
+ acceptedAt?: string;
100
+ submittedAt?: string;
101
+ resultData?: Record<string, unknown> | null;
102
+ verificationResult?: {
103
+ passed: boolean;
104
+ reasons: string[];
105
+ score?: number;
106
+ breakdown?: Array<{
107
+ name: string;
108
+ score: number;
109
+ weight: number;
110
+ reason: string;
111
+ error?: string;
112
+ }>;
113
+ };
114
+ assignTxHash?: Hex;
115
+ verifyTxHash?: Hex;
116
+ wrappedKeys?: Record<string, string>;
117
+ }
118
+ export interface ExecutorProfile {
119
+ address: Address;
120
+ displayName: string;
121
+ capabilities: AgentCapability[];
122
+ publicKey: string;
123
+ reputation: number;
124
+ tasksCompleted: number;
125
+ totalEarnedRaw: string;
126
+ minReward?: string;
127
+ preferredCapabilities?: AgentCapability[];
128
+ registeredAt: string;
129
+ decayedScore?: number;
130
+ disputeRatio?: number;
131
+ avgRating?: number;
132
+ }
133
+ export interface RegisterExecutorInput {
134
+ address: Address;
135
+ displayName: string;
136
+ capabilities: AgentCapability[];
137
+ publicKey: string;
138
+ agentCardUrl?: string;
139
+ mcpEndpointUrl?: string;
140
+ minReward?: string;
141
+ preferredCapabilities?: AgentCapability[];
142
+ }
143
+ /** Params for BlindMarket.createAgent() — generates wallet + registers executor in one call. */
144
+ export interface CreateAgentParams {
145
+ /** Display name for the agent in the marketplace. */
146
+ displayName: string;
147
+ /** Capabilities this agent offers. Use AgentCap.DATA_PROCESSING etc. */
148
+ capabilities: AgentCapability[];
149
+ /** Which of the above the agent prefers (subset of capabilities). */
150
+ preferredCapabilities?: AgentCapability[];
151
+ /** Minimum reward per task (wei string). */
152
+ minReward?: string;
153
+ /** Agent card URL for marketplace display. */
154
+ agentCardUrl?: string;
155
+ /** MCP endpoint URL for tool-based agents. */
156
+ mcpEndpointUrl?: string;
157
+ }
158
+ /** Result of BlindMarket.createAgent(). */
159
+ export interface CreateAgentResult {
160
+ executor: ExecutorProfile;
161
+ wallet: {
162
+ address: Address;
163
+ publicKey: string;
164
+ privateKey: string;
165
+ };
166
+ }
167
+ export interface DeployedAgentInfo {
168
+ id: string;
169
+ name: string;
170
+ ownerAddress: Address;
171
+ walletAddress: Address;
172
+ publicKey: string;
173
+ status: string;
174
+ provider: string;
175
+ model: string;
176
+ capabilities: AgentCapability[];
177
+ inftTokenId?: number;
178
+ deployedAt: string;
179
+ lastActiveAt?: string;
180
+ minReward?: string;
181
+ }
182
+ export interface AgentWalletInfo {
183
+ walletAddress: Address;
184
+ publicKey: string;
185
+ }
186
+ export interface ReputationInfo {
187
+ address: Address;
188
+ onChainScore: number;
189
+ decayedScore: number;
190
+ totalTasks: number;
191
+ disputesLost: number;
192
+ disputeRatio: number;
193
+ }
194
+ export interface LeaderboardEntry extends ReputationInfo {
195
+ rank: number;
196
+ displayName?: string;
197
+ }
198
+ export interface StorageUploadResult {
199
+ rootHash: RootHash;
200
+ size: number;
201
+ }
202
+ export interface Message {
203
+ id: number;
204
+ taskId: string;
205
+ fromAddress: Address;
206
+ toAddress: Address;
207
+ content: string;
208
+ read: boolean;
209
+ createdAt: string;
210
+ }
211
+ export interface AgentSearchResult {
212
+ address: Address;
213
+ displayName: string;
214
+ capabilities: string[];
215
+ avgRating: number;
216
+ reviewCount: number;
217
+ badgeCount: number;
218
+ reputation: number;
219
+ }
220
+ export interface TaskTemplate {
221
+ id: number;
222
+ title: string;
223
+ description: string;
224
+ category: string;
225
+ instructions: string;
226
+ verificationCriteria: Record<string, unknown>;
227
+ requiredCapabilities?: string[];
228
+ estimatedReward?: string;
229
+ }
230
+ export interface VerifyTaskInput {
231
+ taskId: number;
232
+ taskCategory: string;
233
+ taskRequirements: string;
234
+ evidenceSummary: string;
235
+ }
236
+ /** Dot-notation access to valid capability strings. */
237
+ export declare const AgentCap: {
238
+ readonly DATA_PROCESSING: "data_processing";
239
+ readonly WEB_RESEARCH: "web_research";
240
+ readonly CODE_EXECUTION: "code_execution";
241
+ readonly CONTENT_GENERATION: "content_generation";
242
+ readonly API_INTEGRATION: "api_integration";
243
+ readonly TEXT_ANALYSIS: "text_analysis";
244
+ readonly TRANSLATION: "translation";
245
+ readonly SUMMARIZATION: "summarization";
246
+ readonly IMAGE_ANALYSIS: "image_analysis";
247
+ readonly DOCUMENT_PROCESSING: "document_processing";
248
+ readonly MATH_COMPUTATION: "math_computation";
249
+ readonly DATA_EXTRACTION: "data_extraction";
250
+ readonly REPORT_GENERATION: "report_generation";
251
+ readonly CODE_REVIEW: "code_review";
252
+ readonly TESTING: "testing";
253
+ readonly SCHEDULING: "scheduling";
254
+ readonly EMAIL_DRAFTING: "email_drafting";
255
+ readonly SOCIAL_MEDIA: "social_media";
256
+ readonly MARKET_RESEARCH: "market_research";
257
+ readonly COMPETITIVE_ANALYSIS: "competitive_analysis";
258
+ };
259
+ export type AgentCapability = typeof AgentCap[keyof typeof AgentCap];
package/dist/types.js CHANGED
@@ -1 +1,24 @@
1
- export {};
1
+ // ── Agent capabilities ───────────────────────────────────────────────────────
2
+ /** Dot-notation access to valid capability strings. */
3
+ export const AgentCap = {
4
+ DATA_PROCESSING: 'data_processing',
5
+ WEB_RESEARCH: 'web_research',
6
+ CODE_EXECUTION: 'code_execution',
7
+ CONTENT_GENERATION: 'content_generation',
8
+ API_INTEGRATION: 'api_integration',
9
+ TEXT_ANALYSIS: 'text_analysis',
10
+ TRANSLATION: 'translation',
11
+ SUMMARIZATION: 'summarization',
12
+ IMAGE_ANALYSIS: 'image_analysis',
13
+ DOCUMENT_PROCESSING: 'document_processing',
14
+ MATH_COMPUTATION: 'math_computation',
15
+ DATA_EXTRACTION: 'data_extraction',
16
+ REPORT_GENERATION: 'report_generation',
17
+ CODE_REVIEW: 'code_review',
18
+ TESTING: 'testing',
19
+ SCHEDULING: 'scheduling',
20
+ EMAIL_DRAFTING: 'email_drafting',
21
+ SOCIAL_MEDIA: 'social_media',
22
+ MARKET_RESEARCH: 'market_research',
23
+ COMPETITIVE_ANALYSIS: 'competitive_analysis',
24
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blindmarket/sdk",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "BlindMarket SDK — deploy agents, assign workers, verify evidence",
5
5
  "author": "BlindMarket Team",
6
6
  "license": "MIT",
@@ -21,7 +21,14 @@
21
21
  "bounty",
22
22
  "blockchain",
23
23
  "encrypted",
24
- "agent-to-human"
24
+ "agent-to-human",
25
+ "mcp",
26
+ "model-context-protocol",
27
+ "openai-tools",
28
+ "agent-sdk",
29
+ "claude",
30
+ "langchain",
31
+ "vercel-ai-sdk"
25
32
  ],
26
33
  "type": "module",
27
34
  "main": "./dist/index.js",
@@ -30,6 +37,10 @@
30
37
  ".": {
31
38
  "import": "./dist/index.js",
32
39
  "types": "./dist/index.d.ts"
40
+ },
41
+ "./tools": {
42
+ "import": "./dist/tools/index.js",
43
+ "types": "./dist/tools/index.d.ts"
33
44
  }
34
45
  },
35
46
  "scripts": {
@@ -3,7 +3,7 @@ import type { Address, Hex, TaskId, TaskStatus, TxReceiptLike } from '../types.j
3
3
  import { BlindEscrowAbi } from './abi/index.js';
4
4
  import { wrapChainError } from './errors.js';
5
5
 
6
- const STATUS_BY_INDEX: TaskStatus[] = ['funded', 'assigned', 'submitted', 'verified', 'completed', 'cancelled'];
6
+ const STATUS_BY_INDEX: TaskStatus[] = ['funded', 'assigned', 'submitted', 'verified', 'completed', 'cancelled', 'disputed'];
7
7
 
8
8
  export interface CreateTaskArgs {
9
9
  taskHash: Hex;
@@ -23,6 +23,8 @@ export interface OnChainTask {
23
23
  taskHash: Hex;
24
24
  evidenceHash: Hex;
25
25
  status: TaskStatus;
26
+ category: string;
27
+ locationZone: string;
26
28
  createdAt: Date;
27
29
  deadline: Date;
28
30
  }
@@ -45,6 +47,10 @@ export class BlindEscrowClient {
45
47
  /** Create a task and return its id + receipt. Reads the TaskCreated event for the id. */
46
48
  async createTask(args: CreateTaskArgs): Promise<{ taskId: TaskId; receipt: TxReceiptLike }> {
47
49
  try {
50
+ const overrides: ethers.Overrides = {};
51
+ if (args.token === '0x0000000000000000000000000000000000000000') {
52
+ overrides.value = args.amount;
53
+ }
48
54
  const tx = await this.contract.createTask!(
49
55
  args.taskHash,
50
56
  args.token,
@@ -52,6 +58,7 @@ export class BlindEscrowClient {
52
58
  args.category,
53
59
  args.locationZone,
54
60
  args.deadline,
61
+ overrides,
55
62
  );
56
63
  const rec = await tx.wait(1);
57
64
  const taskId = this.extractTaskIdFromReceipt(rec);
@@ -163,10 +170,15 @@ function toReceipt(rec: ethers.ContractTransactionReceipt | null): TxReceiptLike
163
170
  }
164
171
 
165
172
  function decodeTask(taskId: TaskId, raw: ethers.Result): OnChainTask {
166
- // Tuple order from BlindEscrow.getTask(): (agent, worker, token, amount, taskHash,
167
- // evidenceHash, status, createdAt, deadline) — verify against contracts/BlindEscrow.sol.
173
+ // Live Task struct (12 fields) from BlindEscrow.getTask(): agent, worker,
174
+ // token, amount, taskHash, evidenceHash, status, category, locationZone,
175
+ // createdAt, deadline, submissionAttempts. The old decode read createdAt from
176
+ // arr[7] (actually category) and deadline from arr[8] (actually locationZone),
177
+ // yielding Invalid Date and discarding category/locationZone.
168
178
  const arr = raw as unknown as unknown[];
169
179
  const statusIndex = Number(arr[6]);
180
+ const status = STATUS_BY_INDEX[statusIndex];
181
+ if (!status) throw new Error(`BlindEscrow.getTask returned unknown status index ${statusIndex}`);
170
182
  return {
171
183
  taskId,
172
184
  agent: arr[0] as Address,
@@ -175,8 +187,10 @@ function decodeTask(taskId: TaskId, raw: ethers.Result): OnChainTask {
175
187
  amount: BigInt(arr[3] as bigint | number),
176
188
  taskHash: arr[4] as Hex,
177
189
  evidenceHash: arr[5] as Hex,
178
- status: STATUS_BY_INDEX[statusIndex] ?? 'funded',
179
- createdAt: new Date(Number(arr[7] as bigint | number) * 1000),
180
- deadline: new Date(Number(arr[8] as bigint | number) * 1000),
190
+ status,
191
+ category: arr[7] as string,
192
+ locationZone: arr[8] as string,
193
+ createdAt: new Date(Number(arr[9] as bigint | number) * 1000),
194
+ deadline: new Date(Number(arr[10] as bigint | number) * 1000),
181
195
  };
182
196
  }
@@ -5,8 +5,11 @@ import { wrapChainError } from './errors.js';
5
5
 
6
6
  export interface ReputationSnapshot {
7
7
  tasksCompleted: bigint;
8
+ /** Raw on-chain value. NOTE: despite the name, the contract returns the
9
+ * average rating already scaled ×100 (450 = 4.50), NOT a cumulative sum. */
8
10
  totalScore: bigint;
9
11
  disputes: bigint;
12
+ /** 0–5 average rating. */
10
13
  avgScore: number;
11
14
  }
12
15
 
@@ -23,9 +26,11 @@ export class BlindReputationClient {
23
26
  try {
24
27
  const raw = (await this.contract.getReputation!(worker)) as unknown as unknown[];
25
28
  const tasksCompleted = BigInt(raw[0] as bigint | number);
29
+ // raw[1] is already avgScore × 100 (contract getReputation returns the
30
+ // average scaled ×100, "450 = 4.50") — divide by 100 only, NOT by tasks.
26
31
  const totalScore = BigInt(raw[1] as bigint | number);
27
32
  const disputes = BigInt(raw[2] as bigint | number);
28
- const avgScore = tasksCompleted === 0n ? 0 : Number(totalScore) / Number(tasksCompleted);
33
+ const avgScore = Number(totalScore) / 100;
29
34
  return { tasksCompleted, totalScore, disputes, avgScore };
30
35
  } catch (err) {
31
36
  throw wrapChainError(err, 'getReputation');
@@ -1,6 +1,7 @@
1
1
  import { ethers } from 'ethers';
2
2
  import type { Signer as SdkSigner } from '../signer/index.js';
3
- import type { Network } from '../network/index.js';
3
+ import type { EVMNetwork } from './domain-types.js';
4
+ import type { Network } from './domain-types.js';
4
5
  import { BlindEscrowClient } from './BlindEscrowClient.js';
5
6
  import { BlindReputationClient } from './BlindReputationClient.js';
6
7
  import { TaskRegistryClient } from './TaskRegistryClient.js';
@@ -17,15 +18,20 @@ export interface ChainClientOptions {
17
18
  * ethers runner. Reads use provider (or signer's provider); writes require a
18
19
  * signer. To keep the SDK's Signer abstraction decoupled from ethers at the
19
20
  * call sites, we unwrap an EthersSigner's inner ethers.Signer lazily here.
21
+ *
22
+ * Only supports EVM networks.
20
23
  */
21
24
  export class ChainClient {
22
25
  readonly escrow: BlindEscrowClient;
23
26
  readonly registry: TaskRegistryClient;
24
27
  readonly reputation: BlindReputationClient;
25
28
  readonly provider: ethers.Provider;
26
- readonly network: Network;
29
+ readonly network: EVMNetwork;
27
30
 
28
31
  constructor(opts: ChainClientOptions) {
32
+ if (opts.network.chainType !== 'evm') {
33
+ throw new Error(`ChainClient requires an EVM network, got ${opts.network.chainType}`);
34
+ }
29
35
  this.network = opts.network;
30
36
  const provider =
31
37
  opts.provider ??
@@ -52,7 +58,7 @@ function unwrapEthersSigner(signer: SdkSigner | undefined): ethers.Signer | unde
52
58
  return maybe.inner;
53
59
  }
54
60
 
55
- function defaultProvider(network: Network): ethers.Provider {
61
+ function defaultProvider(network: EVMNetwork): ethers.Provider {
56
62
  const url = network.rpc[0];
57
63
  if (!url) throw new Error(`network ${network.name} has no RPC endpoint configured`);
58
64
  return new ethers.JsonRpcProvider(url, { chainId: Number(network.chainId), name: network.name });
@@ -0,0 +1,109 @@
1
+ import type {
2
+ CreateTaskParams,
3
+ DomainReputation,
4
+ DomainTask,
5
+ DomainTaskMeta,
6
+ DomainTxReceipt,
7
+ Network,
8
+ } from './domain-types.js';
9
+
10
+ /**
11
+ * Chain-agnostic interface for BlindMarket on-chain operations.
12
+ *
13
+ * Every supported blockchain provides an adapter that implements this interface,
14
+ * translating domain operations into chain-native contract calls. Consumers
15
+ * (backend, agents, CLI) work against this interface and never need to know
16
+ * which chain they're talking to.
17
+ */
18
+ export interface IBlindMarketChain {
19
+ // ── Chain identity ──────────────────────────────────────────────────────
20
+
21
+ /** The resolved network config this adapter is connected to. */
22
+ readonly network: Network;
23
+
24
+ /** The address of the active signer. */
25
+ getAddress(): Promise<string>;
26
+
27
+ // ── Task lifecycle (BlindEscrow equivalent) ─────────────────────────────
28
+
29
+ /**
30
+ * Create a new task with escrowed funds.
31
+ * Returns the assigned task ID and receipt.
32
+ */
33
+ createTask(params: CreateTaskParams): Promise<{ taskId: bigint; receipt: DomainTxReceipt }>;
34
+
35
+ /** Assign a worker to a funded task. Caller must be the task agent. */
36
+ assignWorker(taskId: bigint, worker: string): Promise<DomainTxReceipt>;
37
+
38
+ /** Submit an evidence hash for an assigned task. Caller must be the worker. */
39
+ submitEvidence(taskId: bigint, evidenceHash: string): Promise<DomainTxReceipt>;
40
+
41
+ /** Complete verification for a submitted task (called by the verifier). */
42
+ completeVerification(taskId: bigint, passed: boolean): Promise<DomainTxReceipt>;
43
+
44
+ /** Cancel a funded/assigned task and return escrow to the agent. */
45
+ cancelTask(taskId: bigint): Promise<DomainTxReceipt>;
46
+
47
+ /** Claim escrow after timeout expiry (agent-side). */
48
+ claimTimeout(taskId: bigint): Promise<DomainTxReceipt>;
49
+
50
+ /** Raise a dispute on a task. */
51
+ raiseDispute(taskId: bigint): Promise<DomainTxReceipt>;
52
+
53
+ /** Resolve a dispute (admin only). */
54
+ resolveDispute(taskId: bigint, workerFavored: boolean): Promise<DomainTxReceipt>;
55
+
56
+ /** Read full on-chain task state. */
57
+ getTask(taskId: bigint): Promise<DomainTask>;
58
+
59
+ /** Check whether a task's deadline has passed. */
60
+ isTaskExpired(taskId: bigint): Promise<boolean>;
61
+
62
+ // ── Task discovery (TaskRegistry equivalent) ────────────────────────────
63
+
64
+ /** Publish task metadata to the on-chain discovery index. */
65
+ publishTask(taskId: bigint, meta: Omit<DomainTaskMeta, 'taskId'> & { taskId?: bigint }): Promise<DomainTxReceipt>;
66
+
67
+ /** Remove a task from the discovery index (called on assignment/completion). */
68
+ closeTask(taskId: bigint): Promise<DomainTxReceipt>;
69
+
70
+ /** Get a page of open task IDs from the discovery index. */
71
+ getOpenTasks(offset: bigint, limit: bigint): Promise<DomainTaskMeta[]>;
72
+
73
+ /** Count of currently open tasks. */
74
+ openTaskCount(): Promise<bigint>;
75
+
76
+ /** Total tasks ever published. */
77
+ totalTasks(): Promise<bigint>;
78
+
79
+ // ── Reputation (BlindReputation equivalent) ─────────────────────────────
80
+
81
+ /** Rate a worker after task completion (score 1-5). */
82
+ rateWorker(worker: string, score: number, taskId: bigint): Promise<DomainTxReceipt>;
83
+
84
+ /** Record a dispute against a worker. */
85
+ recordDispute(worker: string, taskId: bigint): Promise<DomainTxReceipt>;
86
+
87
+ /** Fetch on-chain reputation for a worker. */
88
+ getReputation(worker: string): Promise<DomainReputation>;
89
+
90
+ /** Check if a worker has already been rated for a given task. */
91
+ hasBeenRated(worker: string, taskId: bigint): Promise<boolean>;
92
+
93
+ // ── Agent identity (INFT equivalent) ────────────────────────────────────
94
+
95
+ /** Mint an agent identity token. Returns the token ID and receipt. */
96
+ mintAgent(params: {
97
+ to: string;
98
+ encryptedURI: string;
99
+ metadataHash: string;
100
+ }): Promise<{ tokenId: bigint; receipt: DomainTxReceipt }>;
101
+
102
+ /** Read the encrypted metadata URI for an agent token. */
103
+ getEncryptedURI(tokenId: bigint): Promise<string>;
104
+
105
+ // ── Queries ──────────────────────────────────────────────────────────────
106
+
107
+ /** Get native balance for an address. */
108
+ getBalance(address: string): Promise<bigint>;
109
+ }
@@ -5,11 +5,12 @@ import { wrapChainError } from './errors.js';
5
5
 
6
6
  export interface OpenTaskMeta {
7
7
  taskId: TaskId;
8
- token: Address;
8
+ agent: Address;
9
9
  category: string;
10
10
  locationZone: string;
11
11
  reward: bigint;
12
12
  createdAt: Date;
13
+ isOpen: boolean;
13
14
  }
14
15
 
15
16
  export class TaskRegistryClient {
@@ -23,14 +24,19 @@ export class TaskRegistryClient {
23
24
 
24
25
  async getTaskMeta(taskId: TaskId): Promise<OpenTaskMeta> {
25
26
  try {
27
+ // Live TaskMeta struct order: taskId, agent, category, locationZone,
28
+ // reward, createdAt, isOpen (7 fields). The old decode was off by one
29
+ // field from the start (token/agent/category/locationZone), so BigInt() on
30
+ // the locationZone string threw on every real task.
26
31
  const raw = (await this.contract.getTaskMeta!(taskId)) as unknown as unknown[];
27
32
  return {
28
33
  taskId,
29
- token: raw[0] as Address,
30
- category: raw[1] as string,
31
- locationZone: raw[2] as string,
32
- reward: BigInt(raw[3] as bigint | number),
33
- createdAt: new Date(Number(raw[4] as bigint | number) * 1000),
34
+ agent: raw[1] as Address,
35
+ category: raw[2] as string,
36
+ locationZone: raw[3] as string,
37
+ reward: BigInt(raw[4] as bigint | number),
38
+ createdAt: new Date(Number(raw[5] as bigint | number) * 1000),
39
+ isOpen: Boolean(raw[6]),
34
40
  };
35
41
  } catch (err) {
36
42
  throw wrapChainError(err, 'getTaskMeta');
@@ -39,8 +45,11 @@ export class TaskRegistryClient {
39
45
 
40
46
  async getOpenTasks(offset: bigint, limit: bigint): Promise<TaskId[]> {
41
47
  try {
42
- const ids = (await this.contract.getOpenTasks!(offset, limit)) as unknown as unknown[];
43
- return ids.map((x) => BigInt(x as bigint | number));
48
+ // getOpenTasks returns TaskMeta[] structs, NOT raw ids — extract .taskId
49
+ // (field 0) from each. BigInt()-ing the whole struct tuple threw on any
50
+ // non-empty page.
51
+ const metas = (await this.contract.getOpenTasks!(offset, limit)) as unknown as any[];
52
+ return metas.map((m) => BigInt((m?.taskId ?? m?.[0]) as bigint | number));
44
53
  } catch (err) {
45
54
  throw wrapChainError(err, 'getOpenTasks');
46
55
  }
@@ -0,0 +1,40 @@
1
+ import type { IBlindMarketChain } from './IBlindMarketChain.js';
2
+ import { EVMChainAdapter } from './evm/EVMChainAdapter.js';
3
+ import { resolveNetwork } from '../network/resolve.js';
4
+ import type { Network, NetworkName as PresetName } from '../network/index.js';
5
+ import type { EthersSigner } from '../signer/EthersSigner.js';
6
+
7
+ /**
8
+ * Options for creating a chain adapter via the factory.
9
+ *
10
+ * The factory chooses the correct adapter based on `network.chainType`.
11
+ */
12
+ export interface CreateChainAdapterOptions {
13
+ network: Network | PresetName;
14
+ signer?: EthersSigner;
15
+ }
16
+
17
+ /**
18
+ * Factory: create the correct IBlindMarketChain adapter for the given network.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * // EVM (0G)
23
+ * const chain = createChainAdapter({
24
+ * network: 'og-testnet',
25
+ * signer: new PrivateKeySigner(privkey, provider),
26
+ * });
27
+ * ```
28
+ */
29
+ export function createChainAdapter(opts: CreateChainAdapterOptions): IBlindMarketChain {
30
+ const network = resolveNetwork(opts.network);
31
+
32
+ if (network.chainType !== 'evm') {
33
+ throw new Error(`Unsupported chain type: ${network.chainType}. Only EVM (0G) is supported.`);
34
+ }
35
+
36
+ return new EVMChainAdapter({
37
+ network,
38
+ signer: opts.signer,
39
+ });
40
+ }