@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.
- package/README.md +242 -29
- package/dist/chain/BlindEscrowClient.d.ts +2 -0
- package/dist/chain/BlindEscrowClient.js +19 -7
- package/dist/chain/BlindReputationClient.d.ts +3 -0
- package/dist/chain/BlindReputationClient.js +3 -1
- package/dist/chain/ChainClient.d.ts +6 -3
- package/dist/chain/ChainClient.js +6 -1
- package/dist/chain/IBlindMarketChain.d.ts +74 -0
- package/dist/chain/IBlindMarketChain.js +1 -0
- package/dist/chain/TaskRegistryClient.d.ts +2 -1
- package/dist/chain/TaskRegistryClient.js +15 -7
- package/dist/chain/createChainAdapter.d.ts +25 -0
- package/dist/chain/createChainAdapter.js +24 -0
- package/dist/chain/domain-types.d.ts +77 -0
- package/dist/chain/domain-types.js +1 -0
- package/dist/chain/evm/EVMChainAdapter.d.ts +56 -0
- package/dist/chain/evm/EVMChainAdapter.js +161 -0
- package/dist/chain/evm/index.d.ts +1 -0
- package/dist/chain/evm/index.js +1 -0
- package/dist/chain/index.d.ts +4 -0
- package/dist/chain/index.js +5 -0
- package/dist/crypto/constants.js +1 -1
- package/dist/errors/{BlindBountyError.d.ts → BlindMarketError.d.ts} +1 -1
- package/dist/errors/{BlindBountyError.js → BlindMarketError.js} +1 -1
- package/dist/errors/index.d.ts +1 -1
- package/dist/errors/index.js +1 -1
- package/dist/errors/subclasses.d.ts +9 -9
- package/dist/errors/subclasses.js +9 -9
- package/dist/executor/WorkerRuntime.d.ts +113 -0
- package/dist/executor/WorkerRuntime.js +248 -0
- package/dist/executor/index.d.ts +1 -0
- package/dist/executor/index.js +1 -0
- package/dist/index.d.ts +292 -22
- package/dist/index.js +413 -23
- package/dist/keystore/InMemoryKeyStore.js +2 -2
- package/dist/network/presets.d.ts +33 -5
- package/dist/network/presets.js +35 -8
- package/dist/network/resolve.d.ts +12 -3
- package/dist/network/resolve.js +15 -7
- package/dist/network/types.d.ts +3 -16
- package/dist/signer/EthersSigner.js +1 -1
- package/dist/storage/index.d.ts +0 -1
- package/dist/storage/index.js +1 -1
- package/dist/tools/adapters.d.ts +99 -0
- package/dist/tools/adapters.js +129 -0
- package/dist/tools/helpers.d.ts +9 -0
- package/dist/tools/helpers.js +169 -0
- package/dist/tools/index.d.ts +36 -0
- package/dist/tools/index.js +32 -0
- package/dist/tools/types.d.ts +44 -0
- package/dist/tools/types.js +1 -0
- package/dist/types.d.ts +202 -1
- package/dist/types.js +24 -1
- package/package.json +13 -2
- package/src/chain/BlindEscrowClient.ts +20 -6
- package/src/chain/BlindReputationClient.ts +6 -1
- package/src/chain/ChainClient.ts +9 -3
- package/src/chain/IBlindMarketChain.ts +109 -0
- package/src/chain/TaskRegistryClient.ts +17 -8
- package/src/chain/createChainAdapter.ts +40 -0
- package/src/chain/domain-types.ts +92 -0
- package/src/chain/evm/EVMChainAdapter.ts +212 -0
- package/src/chain/evm/index.ts +1 -0
- package/src/chain/index.ts +6 -0
- package/src/executor/WorkerRuntime.ts +338 -0
- package/src/executor/index.ts +8 -0
- package/src/index.ts +546 -36
- package/src/network/presets.ts +47 -8
- package/src/network/resolve.ts +20 -8
- package/src/network/types.ts +18 -16
- package/src/signer/index.ts +1 -1
- package/src/storage/index.ts +1 -1
- package/src/tools/adapters.ts +177 -0
- package/src/tools/helpers.ts +199 -0
- package/src/tools/index.ts +59 -0
- package/src/tools/types.ts +47 -0
- package/src/types.ts +222 -1
- package/tsconfig.json +2 -1
- package/dist/BlindEscrowClient-CyPuKMge.d.cts +0 -54
- package/dist/BlindEscrowClient-R7iGpE-n.d.ts +0 -54
- package/dist/KeyStore-Be_SSpCt.d.cts +0 -21
- package/dist/KeyStore-k1JgYPJY.d.ts +0 -21
- package/dist/Signer-BnqH_qew.d.cts +0 -38
- package/dist/Signer-LColE0Uo.d.ts +0 -38
- package/dist/Storage-4QOrh7rm.d.ts +0 -17
- package/dist/Storage-Cf4IJRMk.d.cts +0 -17
- package/dist/TaskRegistryClient-Ch6lYqM_.d.ts +0 -24
- package/dist/TaskRegistryClient-CrQjddDc.d.cts +0 -24
- package/dist/aes-J-7HrHze.d.cts +0 -17
- package/dist/aes-J-7HrHze.d.ts +0 -17
- package/dist/agent/index.cjs +0 -425
- package/dist/agent/index.cjs.map +0 -1
- package/dist/agent/index.d.cts +0 -63
- package/dist/agent/index.js.map +0 -1
- package/dist/api/index.cjs +0 -4
- package/dist/api/index.cjs.map +0 -1
- package/dist/api/index.d.cts +0 -2
- package/dist/api/index.js.map +0 -1
- package/dist/chain/index.cjs +0 -2484
- package/dist/chain/index.cjs.map +0 -1
- package/dist/chain/index.d.cts +0 -2305
- package/dist/chain/index.js.map +0 -1
- package/dist/compute/index.cjs +0 -4
- package/dist/compute/index.cjs.map +0 -1
- package/dist/compute/index.d.cts +0 -2
- package/dist/compute/index.js.map +0 -1
- package/dist/crypto/index.cjs +0 -424
- package/dist/crypto/index.cjs.map +0 -1
- package/dist/crypto/index.d.cts +0 -74
- package/dist/crypto/index.js.map +0 -1
- package/dist/errors/index.cjs +0 -136
- package/dist/errors/index.cjs.map +0 -1
- package/dist/errors/index.d.cts +0 -60
- package/dist/errors/index.js.map +0 -1
- package/dist/events/index.cjs +0 -41
- package/dist/events/index.cjs.map +0 -1
- package/dist/events/index.d.cts +0 -61
- package/dist/events/index.js.map +0 -1
- package/dist/index.cjs +0 -4
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -2
- package/dist/index.js.map +0 -1
- package/dist/keystore/index.cjs +0 -335
- package/dist/keystore/index.cjs.map +0 -1
- package/dist/keystore/index.d.cts +0 -23
- package/dist/keystore/index.js.map +0 -1
- package/dist/network/index.cjs +0 -74
- package/dist/network/index.cjs.map +0 -1
- package/dist/network/index.d.cts +0 -36
- package/dist/network/index.js.map +0 -1
- package/dist/signer/index.cjs +0 -121
- package/dist/signer/index.cjs.map +0 -1
- package/dist/signer/index.d.cts +0 -40
- package/dist/signer/index.js.map +0 -1
- package/dist/storage/ZgStorage.d.ts +0 -24
- package/dist/storage/ZgStorage.js +0 -102
- package/dist/storage/index.cjs +0 -221
- package/dist/storage/index.cjs.map +0 -1
- package/dist/storage/index.d.cts +0 -44
- package/dist/storage/index.js.map +0 -1
- package/dist/testing/index.cjs +0 -4
- package/dist/testing/index.cjs.map +0 -1
- package/dist/testing/index.d.cts +0 -2
- package/dist/testing/index.js.map +0 -1
- package/dist/types-BOG5Ub1z.d.cts +0 -31
- package/dist/types-BOG5Ub1z.d.ts +0 -31
- package/dist/types-V7_ZmUb-.d.cts +0 -19
- package/dist/types-hAsITUQ7.d.ts +0 -19
- package/dist/verifier/index.cjs +0 -4
- package/dist/verifier/index.cjs.map +0 -1
- package/dist/verifier/index.d.cts +0 -2
- package/dist/verifier/index.js.map +0 -1
- package/dist/worker/index.cjs +0 -382
- package/dist/worker/index.cjs.map +0 -1
- package/dist/worker/index.d.cts +0 -58
- 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 {
|
|
14
|
+
import { BlindMarket, AgentCap } from '@blindmarket/sdk';
|
|
15
15
|
|
|
16
|
-
const
|
|
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
|
-
//
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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('
|
|
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
|
-
- **
|
|
37
|
-
- **
|
|
38
|
-
- **
|
|
39
|
-
- **
|
|
40
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
52
|
-
worker.getAssignedTask(taskId) // decrypts instructions
|
|
53
|
-
worker.submitEvidence(taskId, evidence)
|
|
205
|
+
### Verification
|
|
54
206
|
|
|
55
|
-
|
|
56
|
-
|
|
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)
|
|
@@ -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
|
|
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
|
-
//
|
|
127
|
-
//
|
|
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
|
|
139
|
-
|
|
140
|
-
|
|
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 =
|
|
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 {
|
|
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
|
|
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:
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
17
|
-
category: raw[
|
|
18
|
-
locationZone: raw[
|
|
19
|
-
reward: BigInt(raw[
|
|
20
|
-
createdAt: new Date(Number(raw[
|
|
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
|
-
|
|
30
|
-
|
|
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
|
+
}
|