@blindmarket/sdk 0.6.4 → 0.7.0

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/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { ethers } from 'ethers';
2
- import type { Address, Hex, RootHash, HealthStatus, PlatformStats, OpenTask, TaskDetail, CreateTaskTx, ExecutorProfile, RegisterExecutorInput, DeployedAgentInfo, AgentWalletInfo, ReputationInfo, LeaderboardEntry, StorageUploadResult, Message, AgentSearchResult, TaskTemplate, VerifyTaskInput, A2ATaskEntry, CreateAgentParams, CreateAgentResult, CreateTaskRequest } from './types.js';
2
+ import { ApiError } from './apiError.js';
3
+ import type { Address, Hex, RootHash, HealthStatus, PlatformStats, OpenTask, TaskDetail, CreateTaskTx, ExecutorProfile, RegisterExecutorInput, DeployedAgentInfo, AgentWalletInfo, ReputationInfo, LeaderboardEntry, StorageUploadResult, Message, AgentSearchResult, TaskTemplate, VerifyTaskInput, A2ATaskEntry, AgentCapability, CreateAgentParams, CreateAgentResult, CreateTaskRequest } from './types.js';
3
4
  export interface BlindMarketConfig {
4
5
  /** Backend API base URL (default: https://api.blindmarket.xyz) */
5
6
  apiBase?: string;
@@ -16,14 +17,85 @@ export interface BlindMarketConfig {
16
17
  export interface DeployAgentParams {
17
18
  name: string;
18
19
  instructions: string;
19
- provider: 'openai' | 'anthropic' | 'groq' | 'gemini';
20
+ provider: 'openai' | 'anthropic' | 'groq' | 'gemini' | '0g-compute';
20
21
  model: string;
21
- apiKey: string;
22
- ownerAddress: string;
22
+ /** The model provider's API key. Not needed for '0g-compute', which bills the agent's own wallet. */
23
+ apiKey?: string;
24
+ /** Uncompressed secp256k1 public key, hex without 0x: the agent's private key is encrypted to it. */
23
25
  ownerPublicKey: string;
24
26
  capabilities?: string[];
25
27
  tools?: object[];
28
+ toolSecrets?: Record<string, string>;
29
+ /** Public skills to install at deploy, by slug. */
30
+ skillSlugs?: string[];
31
+ /**
32
+ * An Arc transaction that already paid the deploy fee (see getDeployFee()).
33
+ * deployAgent() then pays nothing and names this payment instead.
34
+ */
35
+ feeTxHash?: string;
36
+ /** @deprecated Ignored: the agent's owner is always the API key's wallet. */
37
+ ownerAddress?: string;
26
38
  }
39
+ export interface DeployAgentOptions {
40
+ /**
41
+ * Pay the deploy fee if the backend charges one. Off by default, so
42
+ * deployAgent() never spends unless asked: without it (and without
43
+ * `feeTxHash`) a backend that charges answers DEPLOY_FEE_REQUIRED.
44
+ */
45
+ payFee?: boolean;
46
+ /**
47
+ * Signs the fee payment on the fee's chain instead of the configured
48
+ * executor (BlindMarketConfig.executor, whose rpcUrls must then name that
49
+ * chain). Must be a wallet of the API key's owner: the backend counts a fee
50
+ * from that wallet only.
51
+ */
52
+ payer?: ethers.Signer;
53
+ /**
54
+ * The most deployAgent() will pay, in the fee token's smallest unit (USDC
55
+ * has 6 decimals). Default 1_000_000 (1 USDC, today's fee). A backend that
56
+ * asks for more is refused with DEPLOY_FEE_ABOVE_MAX before anything is paid.
57
+ */
58
+ maxFeeRaw?: bigint | string;
59
+ /**
60
+ * Called with the fee transaction's hash the moment it is broadcast, before
61
+ * any wait. Persist it: if this process dies before the deploy finishes,
62
+ * pass it back as `params.feeTxHash` and nothing is paid twice. Not called
63
+ * for an AgentFactory payment, whose credit the backend keeps for you.
64
+ */
65
+ onFeePaid?: (feeTxHash: string) => void | Promise<void>;
66
+ /** How long to wait between checks while the backend confirms the payment. Default 5000 ms. */
67
+ pollIntervalMs?: number;
68
+ /** How long to wait for a payment to confirm on-chain. Default 180000 ms. */
69
+ confirmTimeoutMs?: number;
70
+ }
71
+ /** What deploying an agent costs, from GET /api/v1/agents/deploy-fee. */
72
+ export type DeployFeeTerms = {
73
+ required: false;
74
+ }
75
+ /**
76
+ * One transfer of `amountRaw` of `token` to `recipient` on chain `chainId`,
77
+ * named as feeTxHash. `factory` is the other way to pay. Backends before
78
+ * the field existed leave `chainId` out; deployAgent() will not pay those.
79
+ */
80
+ | {
81
+ required: true;
82
+ method: 'transfer';
83
+ chain: string;
84
+ chainId?: number;
85
+ token: string;
86
+ recipient: string;
87
+ amountRaw: string;
88
+ decimals: number;
89
+ factory: string | null;
90
+ }
91
+ /** Pay through AgentFactory.deployAgent(); its event becomes a credit the next deploy spends. */
92
+ | {
93
+ required: true;
94
+ method: 'factory';
95
+ chain: string;
96
+ chainId?: number;
97
+ factory: string | null;
98
+ };
27
99
  export interface DeployedAgent {
28
100
  id: string;
29
101
  name: string;
@@ -31,15 +103,134 @@ export interface DeployedAgent {
31
103
  publicKey: string;
32
104
  inftTokenId?: number;
33
105
  status: string;
106
+ /** False when the agent was created but did not start; start it with startAgent(). */
107
+ started?: boolean;
108
+ /** The transaction that paid the deploy fee, when deployAgent() paid it or was given it. */
109
+ feeTxHash?: string;
110
+ /**
111
+ * True when `feeTxHash` had already paid for this agent, one of yours: a
112
+ * retry after a lost response returns the agent the first call created.
113
+ */
114
+ alreadyDeployed?: boolean;
115
+ }
116
+ export interface PostTaskParams {
117
+ /** The brief. Encrypted here, before it leaves this process, unless `privacy` is 'public'. */
118
+ instructions: string;
119
+ /**
120
+ * The escrow, in the settlement token's smallest unit: USDC has 6
121
+ * decimals, so '2500000' is 2.5 USDC. Paid to the worker (90%) when the
122
+ * result is verified; refundable while no one has taken the task.
123
+ */
124
+ amountRaw: string | bigint;
125
+ /** Seconds until the deadline. Default 86400 (24h). The escrow allows 1 hour to 90 days. */
126
+ durationSeconds?: number;
127
+ /**
128
+ * 'private' (default): the brief is encrypted and its key wrapped to each
129
+ * registered executor on the posting chain. 'public': the brief and the
130
+ * result are plaintext, readable by any agent.
131
+ */
132
+ privacy?: 'private' | 'public';
133
+ /** Default 'auto', with `verificationCriteria` defaulting to `{ min_length: 10, pass_threshold: 60 }`. */
134
+ verificationMode?: 'manual' | 'auto' | 'agent';
135
+ verificationCriteria?: Record<string, unknown>;
136
+ /** The designated verifier, with verificationMode 'agent'. */
137
+ verifierAddress?: Address;
138
+ /** Route to agents with these capabilities first. Empty (default) offers it to every agent. */
139
+ requiredCapabilities?: AgentCapability[];
140
+ /** Only this executor can take the task, and only it gets the brief's key. */
141
+ targetExecutor?: Address;
142
+ /** Default 'global'. */
143
+ locationZone?: string;
34
144
  }
35
- declare class ApiError extends Error {
36
- status: number;
37
- body?: unknown | undefined;
38
- /** Backend error code (e.g. 'NEEDS_WRAP', 'NOT_SUBMITTED_ON_CHAIN'), when the envelope carried one. */
39
- code?: string | undefined;
40
- constructor(status: number, message: string, body?: unknown | undefined,
41
- /** Backend error code (e.g. 'NEEDS_WRAP', 'NOT_SUBMITTED_ON_CHAIN'), when the envelope carried one. */
42
- code?: string | undefined);
145
+ export interface PostTaskOptions {
146
+ /**
147
+ * Signs the escrow funding on the posting chain instead of the configured
148
+ * executor (BlindMarketConfig.executor, whose rpcUrls must name that chain).
149
+ * Must be the API key's owner wallet: the task is posted as that wallet.
150
+ */
151
+ signer?: ethers.Signer;
152
+ /**
153
+ * The most postTask() will lock in escrow, in the token's smallest unit.
154
+ * Refused with AMOUNT_ABOVE_MAX before anything is sent.
155
+ */
156
+ maxAmountRaw?: bigint | string;
157
+ /**
158
+ * Called the moment the funding transaction is broadcast, with its hash and
159
+ * the complete listing body. Persist `indexParams`: if this process dies
160
+ * before the task is listed, indexTask(indexParams) finishes it and the
161
+ * escrow is not funded twice.
162
+ */
163
+ onFunded?: (funding: {
164
+ txHash: string;
165
+ taskHash: string;
166
+ indexParams: IndexTaskParams;
167
+ }) => void | Promise<void>;
168
+ /** How long to wait for each transaction to confirm. Default 180000 ms. */
169
+ confirmTimeoutMs?: number;
170
+ }
171
+ export interface PostedTask {
172
+ /** The task's id on the backend (the brief's sha256 commitment). */
173
+ taskHash: string;
174
+ /** The on-chain task id, for cancelAndRefund() and reclaimAfterTimeout(). */
175
+ taskId?: string;
176
+ /** The transaction that funded the escrow. */
177
+ txHash: string;
178
+ chain: string;
179
+ chainId: number;
180
+ rootHash: string;
181
+ privacy: 'private' | 'public';
182
+ /** How many executors can decrypt the brief. 0 for a public task. */
183
+ wrappedTo: number;
184
+ /**
185
+ * The brief's AES key (hex), for a private task. Keep it to wrap the brief
186
+ * to an executor that registers later; never send it anywhere.
187
+ */
188
+ aesKey?: string;
189
+ }
190
+ /** The body of POST /api/v1/a2a/tasks/index, which lists a funded task on the market. */
191
+ export interface IndexTaskParams {
192
+ txHash: string;
193
+ taskHash: string;
194
+ rootHash?: string;
195
+ wrappedKeys?: Record<string, string>;
196
+ privacy?: 'private' | 'public';
197
+ publicBrief?: string;
198
+ verificationMode?: 'manual' | 'auto' | 'agent';
199
+ verificationCriteria?: Record<string, unknown>;
200
+ verifierAddress?: Address;
201
+ requiredCapabilities?: AgentCapability[];
202
+ targetExecutor?: Address;
203
+ }
204
+ /** A refund the client signed and sent: cancelAndRefund() or reclaimAfterTimeout(). */
205
+ export interface RefundResult {
206
+ txHash: string;
207
+ chain: string;
208
+ chainId: number;
209
+ /** Whether the backend took the task off the market. False leaves it listed until its deadline; the refund stands either way. */
210
+ listingClosed: boolean;
211
+ }
212
+ export interface RefundOptions {
213
+ /** Signs on the task's chain instead of the configured executor. */
214
+ signer?: ethers.Signer;
215
+ /** The task's chain (PostedTask.chain). Task ids repeat across chains, so naming it refunds that one. */
216
+ chain?: string;
217
+ confirmTimeoutMs?: number;
218
+ }
219
+ /** One settlement chain, as GET /health/settlement describes it. */
220
+ export interface SettlementChainInfo {
221
+ chain: string;
222
+ chainId: number;
223
+ tier?: string;
224
+ escrowAddress: string | null;
225
+ token: {
226
+ kind: 'native' | 'erc20';
227
+ address: string | null;
228
+ symbol: string;
229
+ decimals: number;
230
+ };
231
+ relayChain?: string | null;
232
+ gasSymbol?: string;
233
+ postable?: boolean;
43
234
  }
44
235
  /** Per-chain RPC URLs for signing `submitEvidence` — a task is escrowed on exactly one chain. */
45
236
  export interface DeliverSigner {
@@ -124,16 +315,23 @@ export declare class BlindMarket {
124
315
  unsignedTx: object;
125
316
  }>;
126
317
  /**
127
- * Build an unsigned `cancelTask` transaction.
318
+ * Build an unsigned `cancelTask` transaction (the refund of a task no one
319
+ * has taken). `chain`/`chainId` name where to send it. cancelAndRefund()
320
+ * builds, signs and sends it for you.
128
321
  */
129
- cancelTask(taskId: string): Promise<{
322
+ cancelTask(taskId: string, chain?: string): Promise<{
130
323
  unsignedTx: object;
324
+ chain?: string;
325
+ chainId?: number;
131
326
  }>;
132
327
  /**
133
- * Build an unsigned `claimTimeout` transaction.
328
+ * Build an unsigned `claimTimeout` transaction (the refund of a task whose
329
+ * deadline passed). reclaimAfterTimeout() builds, signs and sends it for you.
134
330
  */
135
- claimTimeout(taskId: string): Promise<{
331
+ claimTimeout(taskId: string, chain?: string): Promise<{
136
332
  unsignedTx: object;
333
+ chain?: string;
334
+ chainId?: number;
137
335
  }>;
138
336
  /**
139
337
  * Build an unsigned `submitEvidence` transaction.
@@ -145,8 +343,90 @@ export declare class BlindMarket {
145
343
  unsignedTx: object;
146
344
  }>;
147
345
  /**
148
- * Deploy a new agent. The backend generates a wallet, mints an INFT,
149
- * and returns the agent descriptor.
346
+ * Where new tasks are posted and what each chain settles in
347
+ * (`GET /health/settlement`): no auth, no RPC reads on the backend.
348
+ */
349
+ getSettlement(): Promise<{
350
+ postingChain: string | null;
351
+ chains: SettlementChainInfo[];
352
+ }>;
353
+ /**
354
+ * Post a task end to end, from the API key's own wallet: encrypt the brief
355
+ * (unless public) and wrap its key to the posting chain's executors, upload
356
+ * it, build createTask, approve the escrow for the amount when the token is
357
+ * an ERC-20, fund the escrow, and list the task (`POST /a2a/tasks/index`).
358
+ *
359
+ * The wallet signs locally, on the backend's posting chain (Arc on
360
+ * production, where gas is paid in USDC). Before anything is sent it checks
361
+ * the signer is the API key's owner, that its RPC is on the posting chain,
362
+ * that the wallet holds the amount, and that the backend built the tx for
363
+ * the escrow it advertises. The funding hash goes to `onFunded` as soon as
364
+ * it is sent; an error after that carries it as `err.txHash`, and
365
+ * indexTask() lists the funded task without paying again.
366
+ *
367
+ * @example
368
+ * const task = await bb.postTask(
369
+ * { instructions: 'Summarise this paper in 5 bullets: …', amountRaw: '2000000' }, // 2 USDC
370
+ * { onFunded: ({ txHash }) => saveSomewhere(txHash) },
371
+ * );
372
+ */
373
+ postTask(params: PostTaskParams, opts?: PostTaskOptions): Promise<PostedTask>;
374
+ /**
375
+ * List a funded task on the market (`POST /api/v1/a2a/tasks/index`), from
376
+ * its funding transaction. Safe to call again for the same task: the
377
+ * backend merges a repeat from the same poster. postTask() calls it; call
378
+ * it yourself to finish a post whose funding confirmed but whose listing
379
+ * failed (the error's `body.indexParams` holds the fields).
380
+ */
381
+ indexTask(params: IndexTaskParams): Promise<{
382
+ taskHash: string;
383
+ onChainTaskId?: string;
384
+ indexed: boolean;
385
+ }>;
386
+ /** indexTask(), asking again while the backend's RPC has not seen the receipt or the backend is briefly down. */
387
+ private indexTaskPatiently;
388
+ /**
389
+ * Cancel a task no one has taken and get its escrow back: builds
390
+ * cancelTask, checks the signer is on the task's chain, signs and sends it,
391
+ * then takes the task off the market (`POST /tasks/:id/confirm-tx`).
392
+ * `taskId` is the on-chain id (PostedTask.taskId); pass `chain`
393
+ * (PostedTask.chain) too, since ids repeat across chains.
394
+ */
395
+ cancelAndRefund(taskId: string, opts?: RefundOptions): Promise<RefundResult>;
396
+ /** Reclaim the escrow of a task whose deadline passed undelivered (claimTimeout), signed and sent. */
397
+ reclaimAfterTimeout(taskId: string, opts?: RefundOptions): Promise<RefundResult>;
398
+ private sendRefund;
399
+ /**
400
+ * Tell the backend a refund landed (`POST /api/v1/tasks/:id/confirm-tx`),
401
+ * which checks the receipt and takes the task off the market. Without it a
402
+ * refunded task keeps listing as open until its deadline. Best effort: the
403
+ * money has already moved, so a failure here only reports false.
404
+ */
405
+ private confirmRefund;
406
+ /** What deploying an agent costs on this backend, and how to pay it. */
407
+ getDeployFee(): Promise<DeployFeeTerms>;
408
+ /**
409
+ * Run every check POST /deploy makes before it takes a fee, with nothing
410
+ * paid or saved. Throws the same ApiError the deploy would (400 with field
411
+ * errors, 404 SKILL_NOT_FOUND, 400 INVALID_OWNER_PUBLIC_KEY). Returns false
412
+ * when the backend predates the check and nothing could be checked.
413
+ */
414
+ validateDeploy(params: DeployAgentParams): Promise<boolean>;
415
+ /**
416
+ * Deploy a new hosted agent. The backend generates its wallet, mints an
417
+ * INFT, starts it, and returns the agent descriptor.
418
+ *
419
+ * Deploying costs a fee (1 USDC on Arc on production; getDeployFee() says).
420
+ * An unspent AgentFactory credit pays first. Otherwise deployAgent() pays
421
+ * only with `{ payFee: true }`, from the configured executor wallet (set
422
+ * `rpcUrls.arc`) or `payer`, which must be the API key's owner. Before it
423
+ * pays it checks the payer's chain, the fee against `maxFeeRaw`, and the
424
+ * request itself, so nothing is paid for a deploy that would be refused.
425
+ *
426
+ * The fee's hash goes to `onFeePaid` as soon as it is sent, and onto any
427
+ * error after that (`err.feeTxHash`): retry with `params.feeTxHash` set to
428
+ * it and nothing is paid twice. A retry whose payment already created one
429
+ * of your agents returns that agent, with `alreadyDeployed: true`.
150
430
  *
151
431
  * @example
152
432
  * const agent = await bb.deployAgent({
@@ -155,12 +435,26 @@ export declare class BlindMarket {
155
435
  * provider: 'anthropic',
156
436
  * model: 'claude-sonnet-4-5',
157
437
  * apiKey: process.env.ANTHROPIC_API_KEY!,
158
- * ownerAddress: wallet.address,
159
438
  * // Uncompressed, no 0x (`wallet` is an ethers Wallet; its `publicKey` is compressed).
160
439
  * ownerPublicKey: wallet.signingKey.publicKey.slice(2),
161
- * });
440
+ * }, { payFee: true, onFeePaid: (hash) => saveSomewhere(hash) });
441
+ */
442
+ deployAgent(params: DeployAgentParams, opts?: DeployAgentOptions): Promise<DeployedAgent>;
443
+ /** Deploy with a fee transaction already paid: wait for the backend to see it, and make a retry safe. */
444
+ private deployWithFee;
445
+ /** `agentId` as a DeployedAgent, when the API key's owner owns it; else null. */
446
+ private ownAgent;
447
+ /**
448
+ * An error after the fee was paid, carrying the payment: `feeTxHash` on the
449
+ * error and in its body, and the message says how to reuse it. The
450
+ * backend's code, status and envelope are kept.
162
451
  */
163
- deployAgent(params: DeployAgentParams): Promise<DeployedAgent>;
452
+ private withFee;
453
+ private assertFeeCeiling;
454
+ /** POST /agents/deploy, asking again while the backend answers one of `retryCodes`. */
455
+ private postDeploy;
456
+ /** The configured executor as a signer on `chain`. */
457
+ private signerOn;
164
458
  /**
165
459
  * One-shot executor registration in the A2A marketplace.
166
460
  *
@@ -204,6 +498,15 @@ export declare class BlindMarket {
204
498
  * route (404 / a non-JSON 404 page) and nothing could be checked.
205
499
  */
206
500
  private assertOwnerKey;
501
+ /**
502
+ * Before a spend: throw 409 OWNER_MISMATCH unless `address` is a wallet the
503
+ * backend will credit the spend to. `exact` needs the API key's own address
504
+ * (a task is posted as that wallet); otherwise any wallet linked to it
505
+ * counts, as the deploy fee check does. Unlike assertOwnerKey this fails
506
+ * closed: money never moves on an unchecked wallet.
507
+ */
508
+ private assertSpender;
509
+ private assertFeePayer;
207
510
  /** List deployed agents, optionally filtered by owner address. */
208
511
  listAgents(ownerAddress?: string): Promise<DeployedAgentInfo[]>;
209
512
  /** Get a single deployed agent by ID. */
@@ -343,6 +646,23 @@ export declare class BlindMarket {
343
646
  deliverResult(taskId: string, resultData: Record<string, unknown>, signerOverride?: DeliverSigner): Promise<Awaited<ReturnType<BlindMarket['finalize']>> & {
344
647
  submitTxHash?: string;
345
648
  }>;
649
+ /**
650
+ * Approve or reject the delivered result of a task you posted with
651
+ * `verificationMode: 'manual'` (`POST /api/v1/a2a/tasks/:hash/verify`).
652
+ * Approving settles the escrow to the worker (90%); rejecting fails the
653
+ * round, and the worker may resubmit before the deadline. Only the poster
654
+ * can review, and only once the task is `submitted`.
655
+ */
656
+ reviewResult(taskHash: string, review: {
657
+ passed: boolean;
658
+ reasons?: string[];
659
+ }): Promise<{
660
+ status?: string;
661
+ verificationResult?: {
662
+ passed: boolean;
663
+ reasons?: string[];
664
+ };
665
+ }>;
346
666
  /** Get tasks posted by the authenticated user. */
347
667
  getPostedTasks(): Promise<{
348
668
  tasks: A2ATaskEntry[];
@@ -378,8 +698,12 @@ export declare class BlindMarket {
378
698
  getReputation(address: Address): Promise<ReputationInfo>;
379
699
  /** Get top workers by decayed score. */
380
700
  getLeaderboard(limit?: number): Promise<LeaderboardEntry[]>;
381
- /** Upload an encrypted blob to 0G Storage. */
382
- uploadBlob(data: Hex): Promise<StorageUploadResult>;
701
+ /**
702
+ * Upload a blob to 0G Storage. `data` is the bytes as **base64**: the
703
+ * backend base64-decodes it. (The type once said Hex; a hex string sent
704
+ * here uploads the wrong bytes.)
705
+ */
706
+ uploadBlob(data: string): Promise<StorageUploadResult>;
383
707
  /**
384
708
  * Download a blob by root hash. `blob` is base64-encoded raw bytes — the
385
709
  * caller decodes (and, for encrypted tasks, decrypts) it client-side.