@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/README.md CHANGED
@@ -11,51 +11,264 @@ npm install @blindmarket/sdk
11
11
  ## Quick Start
12
12
 
13
13
  ```ts
14
- import { Agent, PrivateKeySigner, ogTestnet } from '@blindmarket/sdk';
14
+ import { BlindMarket, AgentCap } from '@blindmarket/sdk';
15
15
 
16
- const signer = new PrivateKeySigner(process.env.PRIVATE_KEY!);
17
-
18
- const agent = new Agent({
19
- signer,
20
- network: ogTestnet,
16
+ const bb = new BlindMarket({
17
+ apiKey: process.env.BLINDMARKET_API_KEY!,
21
18
  });
22
19
 
23
- // Post an encrypted task
24
- const { taskId } = await agent.createTask({
25
- instructions: 'Photograph the storefront at 123 Main St',
26
- amount: '100', // USDC
27
- token: '0x3af9...',
28
- durationSeconds: 86400, // 24h
20
+ // Check the platform is live
21
+ const health = await bb.health();
22
+ console.log('Status:', health.status);
23
+
24
+ // Register as an A2A executor (generates wallet + registers in one call)
25
+ const { executor, wallet } = await bb.createAgent({
26
+ displayName: 'DataBot',
27
+ capabilities: [
28
+ AgentCap.DATA_PROCESSING,
29
+ AgentCap.WEB_RESEARCH,
30
+ AgentCap.DATA_EXTRACTION,
31
+ ],
32
+ minReward: '1000000000000000000', // 1 0G in wei
29
33
  });
30
34
 
31
- console.log('Task created:', taskId);
35
+ console.log('Executor:', executor.address);
36
+ console.log('Private key (store securely):', wallet.privateKey);
32
37
  ```
33
38
 
34
39
  ## Features
35
40
 
36
- - **AES-256-GCM** encryption for task instructions and evidence
37
- - **ECIES** key wrapping — only the assigned worker can decrypt
38
- - **0G Storage** — encrypted blobs stored on decentralized storage
39
- - **0G Sealed Inference** — TEE-verified evidence evaluation
40
- - Full task lifecycle: create → assign → submit → verify → pay
41
+ - **Full REST API client** — task lifecycle, agent management, A2A, marketplace, messages, reputation
42
+ - **Event watching** — poll task/agent status with `watchTask()` / `watchAgent()`
43
+ - **Low-level crypto + chain** — `Agent`, `Worker`, `PrivateKeySigner` classes for direct on-chain ops
44
+ - **Framework-agnostic tools** — OpenAI-compatible tool definitions work with LangChain, Vercel AI SDK, Claude SDK, and more
45
+
46
+ ## Framework Integration
47
+
48
+ One import (`BlindMarket` + `tools`), one call, property-access the format for your framework:
49
+
50
+ ### LangChain
51
+
52
+ ```ts
53
+ import { BlindMarket, tools } from '@blindmarket/sdk';
54
+ import { createReactAgent } from '@langchain/langgraph/prebuilt';
55
+ import { ChatOpenAI } from '@langchain/openai';
56
+
57
+ const bb = new BlindMarket({ apiKey: process.env.BLINDMARKET_API_KEY! });
58
+
59
+ const agent = createReactAgent({
60
+ llm: new ChatOpenAI({ model: 'gpt-4' }),
61
+ tools: tools(bb).langchain,
62
+ });
63
+
64
+ await agent.invoke({
65
+ messages: [{ role: 'user', content: 'Find data processing tasks I can accept' }],
66
+ });
67
+ ```
68
+
69
+ ### Vercel AI SDK
70
+
71
+ ```ts
72
+ import { BlindMarket, tools } from '@blindmarket/sdk';
73
+ import { generateText } from 'ai';
74
+ import { openai } from '@ai-sdk/openai';
75
+
76
+ const bb = new BlindMarket({ apiKey: process.env.BLINDMARKET_API_KEY! });
77
+
78
+ const { text } = await generateText({
79
+ model: openai('gpt-4'),
80
+ tools: tools(bb).vercel,
81
+ prompt: 'Find data processing tasks and register me as an executor',
82
+ });
83
+ ```
84
+
85
+ ### OpenAI / OpenAI Agents SDK
86
+
87
+ ```ts
88
+ import { BlindMarket, tools } from '@blindmarket/sdk';
89
+
90
+ const bb = new BlindMarket({ apiKey: process.env.BLINDMARKET_API_KEY! });
91
+
92
+ const response = await openai.chat.completions.create({
93
+ model: 'gpt-4',
94
+ tools: tools(bb).definitions,
95
+ messages: [{ role: 'user', content: 'Find data processing tasks' }],
96
+ });
97
+ ```
98
+
99
+ ### Claude (Anthropic SDK)
100
+
101
+ ```ts
102
+ import { BlindMarket, tools } from '@blindmarket/sdk';
103
+ import Anthropic from '@anthropic-ai/sdk';
104
+
105
+ const bb = new BlindMarket({ apiKey: process.env.BLINDMARKET_API_KEY! });
106
+
107
+ const response = await anthropic.messages.create({
108
+ model: 'claude-sonnet-4-20250514',
109
+ tools: tools(bb).claude,
110
+ messages: [{ role: 'user', content: 'Register me as an executor and find tasks' }],
111
+ });
112
+ ```
113
+
114
+ ## Usage
115
+
116
+ ### Task lifecycle
117
+
118
+ ```ts
119
+ // List open tasks
120
+ const tasks = await bb.listTasks();
121
+
122
+ // Get task details (includes A2A state + verification result)
123
+ const task = await bb.getTask(taskId);
124
+
125
+ // Build unsigned createTask tx (sign & broadcast with your wallet)
126
+ const { unsignedTx } = await bb.createTask({
127
+ agent: wallet.address,
128
+ amount: '100',
129
+ token: '0x317227efcA18D004E12CA8046AEf7E1597458F25',
130
+ category: 'photography',
131
+ locationZone: 'nyc',
132
+ deadline: Math.floor(Date.now() / 1000) + 86400,
133
+ });
134
+ ```
135
+
136
+ ### Agent management
137
+
138
+ ```ts
139
+ // List agents
140
+ const agents = await bb.listAgents(wallet.address);
141
+
142
+ // Get single agent
143
+ const agent = await bb.getAgent(agentId);
144
+
145
+ // Start/stop/pause/restart
146
+ await bb.startAgent(agentId);
147
+ await bb.pauseAgent(agentId);
148
+ await bb.stopAgent(agentId);
41
149
 
42
- ## API
150
+ // Update config
151
+ await bb.updateAgent(agentId, {
152
+ instructions: 'New instructions',
153
+ model: 'gpt-4',
154
+ minReward: '1000000000000000000', // 1 0G in wei
155
+ });
156
+ ```
157
+
158
+ ### A2A (agent-to-agent task execution)
159
+
160
+ ```ts
161
+ // Register as an executor
162
+ await bb.registerExecutor({
163
+ address: wallet.address,
164
+ displayName: 'my-agent',
165
+ capabilities: ['data_processing', 'web_research'],
166
+ publicKey: wallet.publicKey,
167
+ });
168
+
169
+ // Browse available tasks
170
+ const { tasks } = await bb.browseA2ATasks({
171
+ capabilities: ['data_processing'],
172
+ });
173
+
174
+ // Bid and accept
175
+ await bb.bidOnTask(taskId);
176
+ const { task, wrappedKey } = await bb.acceptTask(taskId);
177
+
178
+ // Submit result
179
+ await bb.submitResult(taskId, {
180
+ output: 'Task completed successfully',
181
+ });
182
+
183
+ // Check posted/executed tasks
184
+ const posted = await bb.getPostedTasks();
185
+ const executed = await bb.getExecutions();
186
+ ```
187
+
188
+ ### Event watching
43
189
 
44
190
  ```ts
45
- // Agent
46
- agent.createTask(options)
47
- agent.assignWorker(taskId, workerAddress)
48
- agent.triggerVerification(taskId)
49
- agent.cancelTask(taskId)
191
+ // Watch a task for status changes
192
+ const stop = bb.watchTask(taskId, (task) => {
193
+ console.log('New status:', task.status);
194
+ if (task.status === 'verified' || task.status === 'failed') {
195
+ stop(); // Stop polling when terminal
196
+ }
197
+ });
198
+
199
+ // Watch an agent
200
+ const stopAgent = bb.watchAgent(agentId, (agent) => {
201
+ console.log('Agent status:', agent.status);
202
+ });
203
+ ```
50
204
 
51
- // Worker
52
- worker.getAssignedTask(taskId) // decrypts instructions
53
- worker.submitEvidence(taskId, evidence)
205
+ ### Verification
54
206
 
55
- // Reputation
56
- client.getReputation(address)
207
+ ```ts
208
+ const result = await bb.verify({
209
+ taskId: 42,
210
+ taskCategory: 'photography',
211
+ taskRequirements: 'Photo must show the storefront clearly',
212
+ evidenceSummary: 'Photo shows 123 Main St storefront',
213
+ });
214
+ console.log('Passed:', result.passed, 'TEE verified:', result.teeVerified);
57
215
  ```
58
216
 
217
+ ### Messages
218
+
219
+ ```ts
220
+ await bb.sendMessage({
221
+ taskId: '42',
222
+ to: agentAddress,
223
+ content: 'Please clarify the instructions',
224
+ });
225
+
226
+ const { messages } = await bb.getInbox();
227
+ const { count } = await bb.getUnreadCount();
228
+ ```
229
+
230
+ ### Marketplace
231
+
232
+ ```ts
233
+ // Search agents by capability
234
+ const results = await bb.searchAgents({
235
+ capability: 'data_processing',
236
+ minRating: 4,
237
+ });
238
+
239
+ // Task templates
240
+ const templates = await bb.listTemplates();
241
+ const myTemplate = await bb.createTemplate({
242
+ title: 'Photo verification',
243
+ description: 'Take a photo of a storefront',
244
+ category: 'photography',
245
+ });
246
+ ```
247
+
248
+ ### Reputation
249
+
250
+ ```ts
251
+ const rep = await bb.getReputation(wallet.address);
252
+ const leaderboard = await bb.getLeaderboard(10);
253
+ ```
254
+
255
+ ### Storage
256
+
257
+ ```ts
258
+ const { rootHash } = await bb.uploadBlob('0x...');
259
+ const { data } = await bb.downloadBlob(rootHash);
260
+ ```
261
+
262
+ ## Low-level API
263
+
264
+ For on-chain operations (signing, broadcasting, encrypting), use the primitive classes:
265
+
266
+ ```ts
267
+ import { Agent, Worker, PrivateKeySigner, ZgStorage, ogTestnet } from '@blindmarket/sdk';
268
+ ```
269
+
270
+ See the [source](https://github.com/JemIIahh/BlindMarket/tree/main/sdk/src) for full documentation.
271
+
59
272
  ## Network
60
273
 
61
274
  Deployed on **0G Testnet Galileo** (Chain ID: 16602)
@@ -17,6 +17,8 @@ export interface OnChainTask {
17
17
  taskHash: Hex;
18
18
  evidenceHash: Hex;
19
19
  status: TaskStatus;
20
+ category: string;
21
+ locationZone: string;
20
22
  createdAt: Date;
21
23
  deadline: Date;
22
24
  }
@@ -1,7 +1,7 @@
1
1
  import { ethers } from 'ethers';
2
2
  import { BlindEscrowAbi } from './abi/index.js';
3
3
  import { wrapChainError } from './errors.js';
4
- const STATUS_BY_INDEX = ['funded', 'assigned', 'submitted', 'verified', 'completed', 'cancelled'];
4
+ const STATUS_BY_INDEX = ['funded', 'assigned', 'submitted', 'verified', 'completed', 'cancelled', 'disputed'];
5
5
  /**
6
6
  * Typed ethers v6 wrapper for the BlindEscrow contract. Every state-changing
7
7
  * method awaits one confirmation and returns a TxReceiptLike; every read
@@ -18,7 +18,11 @@ export class BlindEscrowClient {
18
18
  /** Create a task and return its id + receipt. Reads the TaskCreated event for the id. */
19
19
  async createTask(args) {
20
20
  try {
21
- const tx = await this.contract.createTask(args.taskHash, args.token, args.amount, args.category, args.locationZone, args.deadline);
21
+ const overrides = {};
22
+ if (args.token === '0x0000000000000000000000000000000000000000') {
23
+ overrides.value = args.amount;
24
+ }
25
+ const tx = await this.contract.createTask(args.taskHash, args.token, args.amount, args.category, args.locationZone, args.deadline, overrides);
22
26
  const rec = await tx.wait(1);
23
27
  const taskId = this.extractTaskIdFromReceipt(rec);
24
28
  return { taskId, receipt: toReceipt(rec) };
@@ -123,10 +127,16 @@ function toReceipt(rec) {
123
127
  };
124
128
  }
125
129
  function decodeTask(taskId, raw) {
126
- // Tuple order from BlindEscrow.getTask(): (agent, worker, token, amount, taskHash,
127
- // evidenceHash, status, createdAt, deadline) — verify against contracts/BlindEscrow.sol.
130
+ // Live Task struct (12 fields) from BlindEscrow.getTask(): agent, worker,
131
+ // token, amount, taskHash, evidenceHash, status, category, locationZone,
132
+ // createdAt, deadline, submissionAttempts. The old decode read createdAt from
133
+ // arr[7] (actually category) and deadline from arr[8] (actually locationZone),
134
+ // yielding Invalid Date and discarding category/locationZone.
128
135
  const arr = raw;
129
136
  const statusIndex = Number(arr[6]);
137
+ const status = STATUS_BY_INDEX[statusIndex];
138
+ if (!status)
139
+ throw new Error(`BlindEscrow.getTask returned unknown status index ${statusIndex}`);
130
140
  return {
131
141
  taskId,
132
142
  agent: arr[0],
@@ -135,8 +145,10 @@ function decodeTask(taskId, raw) {
135
145
  amount: BigInt(arr[3]),
136
146
  taskHash: arr[4],
137
147
  evidenceHash: arr[5],
138
- status: STATUS_BY_INDEX[statusIndex] ?? 'funded',
139
- createdAt: new Date(Number(arr[7]) * 1000),
140
- deadline: new Date(Number(arr[8]) * 1000),
148
+ status,
149
+ category: arr[7],
150
+ locationZone: arr[8],
151
+ createdAt: new Date(Number(arr[9]) * 1000),
152
+ deadline: new Date(Number(arr[10]) * 1000),
141
153
  };
142
154
  }
@@ -2,8 +2,11 @@ import { ethers } from 'ethers';
2
2
  import type { Address, TaskId, TxReceiptLike } from '../types.js';
3
3
  export interface ReputationSnapshot {
4
4
  tasksCompleted: bigint;
5
+ /** Raw on-chain value. NOTE: despite the name, the contract returns the
6
+ * average rating already scaled ×100 (450 = 4.50), NOT a cumulative sum. */
5
7
  totalScore: bigint;
6
8
  disputes: bigint;
9
+ /** 0–5 average rating. */
7
10
  avgScore: number;
8
11
  }
9
12
  export declare class BlindReputationClient {
@@ -12,9 +12,11 @@ export class BlindReputationClient {
12
12
  try {
13
13
  const raw = (await this.contract.getReputation(worker));
14
14
  const tasksCompleted = BigInt(raw[0]);
15
+ // raw[1] is already avgScore × 100 (contract getReputation returns the
16
+ // average scaled ×100, "450 = 4.50") — divide by 100 only, NOT by tasks.
15
17
  const totalScore = BigInt(raw[1]);
16
18
  const disputes = BigInt(raw[2]);
17
- const avgScore = tasksCompleted === 0n ? 0 : Number(totalScore) / Number(tasksCompleted);
19
+ const avgScore = Number(totalScore) / 100;
18
20
  return { tasksCompleted, totalScore, disputes, avgScore };
19
21
  }
20
22
  catch (err) {
@@ -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';
@@ -11,16 +12,18 @@ export interface ChainClientOptions {
11
12
  provider?: ethers.Provider;
12
13
  }
13
14
  /**
14
- * Bundles typed clients for all three BlindBounty contracts plus the underlying
15
+ * Bundles typed clients for all three BlindMarket contracts plus the underlying
15
16
  * ethers runner. Reads use provider (or signer's provider); writes require a
16
17
  * signer. To keep the SDK's Signer abstraction decoupled from ethers at the
17
18
  * call sites, we unwrap an EthersSigner's inner ethers.Signer lazily here.
19
+ *
20
+ * Only supports EVM networks.
18
21
  */
19
22
  export declare class ChainClient {
20
23
  readonly escrow: BlindEscrowClient;
21
24
  readonly registry: TaskRegistryClient;
22
25
  readonly reputation: BlindReputationClient;
23
26
  readonly provider: ethers.Provider;
24
- readonly network: Network;
27
+ readonly network: EVMNetwork;
25
28
  constructor(opts: ChainClientOptions);
26
29
  }
@@ -3,10 +3,12 @@ import { BlindEscrowClient } from './BlindEscrowClient.js';
3
3
  import { BlindReputationClient } from './BlindReputationClient.js';
4
4
  import { TaskRegistryClient } from './TaskRegistryClient.js';
5
5
  /**
6
- * Bundles typed clients for all three BlindBounty contracts plus the underlying
6
+ * Bundles typed clients for all three BlindMarket contracts plus the underlying
7
7
  * ethers runner. Reads use provider (or signer's provider); writes require a
8
8
  * signer. To keep the SDK's Signer abstraction decoupled from ethers at the
9
9
  * call sites, we unwrap an EthersSigner's inner ethers.Signer lazily here.
10
+ *
11
+ * Only supports EVM networks.
10
12
  */
11
13
  export class ChainClient {
12
14
  escrow;
@@ -15,6 +17,9 @@ export class ChainClient {
15
17
  provider;
16
18
  network;
17
19
  constructor(opts) {
20
+ if (opts.network.chainType !== 'evm') {
21
+ throw new Error(`ChainClient requires an EVM network, got ${opts.network.chainType}`);
22
+ }
18
23
  this.network = opts.network;
19
24
  const provider = opts.provider ??
20
25
  (opts.signer && unwrapEthersSigner(opts.signer)?.provider) ??
@@ -0,0 +1,74 @@
1
+ import type { CreateTaskParams, DomainReputation, DomainTask, DomainTaskMeta, DomainTxReceipt, Network } from './domain-types.js';
2
+ /**
3
+ * Chain-agnostic interface for BlindMarket on-chain operations.
4
+ *
5
+ * Every supported blockchain provides an adapter that implements this interface,
6
+ * translating domain operations into chain-native contract calls. Consumers
7
+ * (backend, agents, CLI) work against this interface and never need to know
8
+ * which chain they're talking to.
9
+ */
10
+ export interface IBlindMarketChain {
11
+ /** The resolved network config this adapter is connected to. */
12
+ readonly network: Network;
13
+ /** The address of the active signer. */
14
+ getAddress(): Promise<string>;
15
+ /**
16
+ * Create a new task with escrowed funds.
17
+ * Returns the assigned task ID and receipt.
18
+ */
19
+ createTask(params: CreateTaskParams): Promise<{
20
+ taskId: bigint;
21
+ receipt: DomainTxReceipt;
22
+ }>;
23
+ /** Assign a worker to a funded task. Caller must be the task agent. */
24
+ assignWorker(taskId: bigint, worker: string): Promise<DomainTxReceipt>;
25
+ /** Submit an evidence hash for an assigned task. Caller must be the worker. */
26
+ submitEvidence(taskId: bigint, evidenceHash: string): Promise<DomainTxReceipt>;
27
+ /** Complete verification for a submitted task (called by the verifier). */
28
+ completeVerification(taskId: bigint, passed: boolean): Promise<DomainTxReceipt>;
29
+ /** Cancel a funded/assigned task and return escrow to the agent. */
30
+ cancelTask(taskId: bigint): Promise<DomainTxReceipt>;
31
+ /** Claim escrow after timeout expiry (agent-side). */
32
+ claimTimeout(taskId: bigint): Promise<DomainTxReceipt>;
33
+ /** Raise a dispute on a task. */
34
+ raiseDispute(taskId: bigint): Promise<DomainTxReceipt>;
35
+ /** Resolve a dispute (admin only). */
36
+ resolveDispute(taskId: bigint, workerFavored: boolean): Promise<DomainTxReceipt>;
37
+ /** Read full on-chain task state. */
38
+ getTask(taskId: bigint): Promise<DomainTask>;
39
+ /** Check whether a task's deadline has passed. */
40
+ isTaskExpired(taskId: bigint): Promise<boolean>;
41
+ /** Publish task metadata to the on-chain discovery index. */
42
+ publishTask(taskId: bigint, meta: Omit<DomainTaskMeta, 'taskId'> & {
43
+ taskId?: bigint;
44
+ }): Promise<DomainTxReceipt>;
45
+ /** Remove a task from the discovery index (called on assignment/completion). */
46
+ closeTask(taskId: bigint): Promise<DomainTxReceipt>;
47
+ /** Get a page of open task IDs from the discovery index. */
48
+ getOpenTasks(offset: bigint, limit: bigint): Promise<DomainTaskMeta[]>;
49
+ /** Count of currently open tasks. */
50
+ openTaskCount(): Promise<bigint>;
51
+ /** Total tasks ever published. */
52
+ totalTasks(): Promise<bigint>;
53
+ /** Rate a worker after task completion (score 1-5). */
54
+ rateWorker(worker: string, score: number, taskId: bigint): Promise<DomainTxReceipt>;
55
+ /** Record a dispute against a worker. */
56
+ recordDispute(worker: string, taskId: bigint): Promise<DomainTxReceipt>;
57
+ /** Fetch on-chain reputation for a worker. */
58
+ getReputation(worker: string): Promise<DomainReputation>;
59
+ /** Check if a worker has already been rated for a given task. */
60
+ hasBeenRated(worker: string, taskId: bigint): Promise<boolean>;
61
+ /** Mint an agent identity token. Returns the token ID and receipt. */
62
+ mintAgent(params: {
63
+ to: string;
64
+ encryptedURI: string;
65
+ metadataHash: string;
66
+ }): Promise<{
67
+ tokenId: bigint;
68
+ receipt: DomainTxReceipt;
69
+ }>;
70
+ /** Read the encrypted metadata URI for an agent token. */
71
+ getEncryptedURI(tokenId: bigint): Promise<string>;
72
+ /** Get native balance for an address. */
73
+ getBalance(address: string): Promise<bigint>;
74
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -2,11 +2,12 @@ import { ethers } from 'ethers';
2
2
  import type { Address, TaskId, TxReceiptLike } from '../types.js';
3
3
  export interface OpenTaskMeta {
4
4
  taskId: TaskId;
5
- token: Address;
5
+ agent: Address;
6
6
  category: string;
7
7
  locationZone: string;
8
8
  reward: bigint;
9
9
  createdAt: Date;
10
+ isOpen: boolean;
10
11
  }
11
12
  export declare class TaskRegistryClient {
12
13
  readonly contract: ethers.Contract;
@@ -10,14 +10,19 @@ export class TaskRegistryClient {
10
10
  }
11
11
  async getTaskMeta(taskId) {
12
12
  try {
13
+ // Live TaskMeta struct order: taskId, agent, category, locationZone,
14
+ // reward, createdAt, isOpen (7 fields). The old decode was off by one
15
+ // field from the start (token/agent/category/locationZone), so BigInt() on
16
+ // the locationZone string threw on every real task.
13
17
  const raw = (await this.contract.getTaskMeta(taskId));
14
18
  return {
15
19
  taskId,
16
- token: raw[0],
17
- category: raw[1],
18
- locationZone: raw[2],
19
- reward: BigInt(raw[3]),
20
- createdAt: new Date(Number(raw[4]) * 1000),
20
+ agent: raw[1],
21
+ category: raw[2],
22
+ locationZone: raw[3],
23
+ reward: BigInt(raw[4]),
24
+ createdAt: new Date(Number(raw[5]) * 1000),
25
+ isOpen: Boolean(raw[6]),
21
26
  };
22
27
  }
23
28
  catch (err) {
@@ -26,8 +31,11 @@ export class TaskRegistryClient {
26
31
  }
27
32
  async getOpenTasks(offset, limit) {
28
33
  try {
29
- const ids = (await this.contract.getOpenTasks(offset, limit));
30
- return ids.map((x) => BigInt(x));
34
+ // getOpenTasks returns TaskMeta[] structs, NOT raw ids — extract .taskId
35
+ // (field 0) from each. BigInt()-ing the whole struct tuple threw on any
36
+ // non-empty page.
37
+ const metas = (await this.contract.getOpenTasks(offset, limit));
38
+ return metas.map((m) => BigInt((m?.taskId ?? m?.[0])));
31
39
  }
32
40
  catch (err) {
33
41
  throw wrapChainError(err, 'getOpenTasks');
@@ -0,0 +1,25 @@
1
+ import type { IBlindMarketChain } from './IBlindMarketChain.js';
2
+ import type { Network, NetworkName as PresetName } from '../network/index.js';
3
+ import type { EthersSigner } from '../signer/EthersSigner.js';
4
+ /**
5
+ * Options for creating a chain adapter via the factory.
6
+ *
7
+ * The factory chooses the correct adapter based on `network.chainType`.
8
+ */
9
+ export interface CreateChainAdapterOptions {
10
+ network: Network | PresetName;
11
+ signer?: EthersSigner;
12
+ }
13
+ /**
14
+ * Factory: create the correct IBlindMarketChain adapter for the given network.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * // EVM (0G)
19
+ * const chain = createChainAdapter({
20
+ * network: 'og-testnet',
21
+ * signer: new PrivateKeySigner(privkey, provider),
22
+ * });
23
+ * ```
24
+ */
25
+ export declare function createChainAdapter(opts: CreateChainAdapterOptions): IBlindMarketChain;
@@ -0,0 +1,24 @@
1
+ import { EVMChainAdapter } from './evm/EVMChainAdapter.js';
2
+ import { resolveNetwork } from '../network/resolve.js';
3
+ /**
4
+ * Factory: create the correct IBlindMarketChain adapter for the given network.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * // EVM (0G)
9
+ * const chain = createChainAdapter({
10
+ * network: 'og-testnet',
11
+ * signer: new PrivateKeySigner(privkey, provider),
12
+ * });
13
+ * ```
14
+ */
15
+ export function createChainAdapter(opts) {
16
+ const network = resolveNetwork(opts.network);
17
+ if (network.chainType !== 'evm') {
18
+ throw new Error(`Unsupported chain type: ${network.chainType}. Only EVM (0G) is supported.`);
19
+ }
20
+ return new EVMChainAdapter({
21
+ network,
22
+ signer: opts.signer,
23
+ });
24
+ }