@blindmarket/sdk 0.1.7 → 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/dist/chain/BlindEscrowClient.d.ts +2 -0
- package/dist/chain/BlindEscrowClient.js +14 -6
- package/dist/chain/BlindReputationClient.d.ts +3 -0
- package/dist/chain/BlindReputationClient.js +3 -1
- package/dist/chain/ChainClient.d.ts +5 -2
- package/dist/chain/ChainClient.js +5 -0
- 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/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 +7 -0
- package/dist/index.js +8 -3
- 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/types.d.ts +1 -1
- package/package.json +1 -1
- package/src/chain/BlindEscrowClient.ts +15 -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 +23 -4
- 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/types.ts +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/BlindBountyError.d.ts +0 -14
- package/dist/errors/BlindBountyError.js +0 -30
- 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/mcp.d.ts +0 -23
- package/dist/mcp.js +0 -101
- 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
|
@@ -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
|
|
@@ -127,10 +127,16 @@ function toReceipt(rec) {
|
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
129
|
function decodeTask(taskId, raw) {
|
|
130
|
-
//
|
|
131
|
-
//
|
|
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.
|
|
132
135
|
const arr = raw;
|
|
133
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}`);
|
|
134
140
|
return {
|
|
135
141
|
taskId,
|
|
136
142
|
agent: arr[0],
|
|
@@ -139,8 +145,10 @@ function decodeTask(taskId, raw) {
|
|
|
139
145
|
amount: BigInt(arr[3]),
|
|
140
146
|
taskHash: arr[4],
|
|
141
147
|
evidenceHash: arr[5],
|
|
142
|
-
status
|
|
143
|
-
|
|
144
|
-
|
|
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),
|
|
145
153
|
};
|
|
146
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';
|
|
@@ -15,12 +16,14 @@ export interface ChainClientOptions {
|
|
|
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
|
}
|
|
@@ -7,6 +7,8 @@ import { TaskRegistryClient } from './TaskRegistryClient.js';
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { Address, Hex, TaskId, TaskStatus } from '../types.js';
|
|
2
|
+
export type BlockchainType = 'evm';
|
|
3
|
+
/** Base fields shared by all chain network configs. */
|
|
4
|
+
export interface NetworkBase {
|
|
5
|
+
name: string;
|
|
6
|
+
chainType: BlockchainType;
|
|
7
|
+
rpc: string[];
|
|
8
|
+
explorer?: string;
|
|
9
|
+
}
|
|
10
|
+
/** EVM-compatible chain network config (0G, Ethereum, Polygon, etc.). */
|
|
11
|
+
export interface EVMNetwork extends NetworkBase {
|
|
12
|
+
chainType: 'evm';
|
|
13
|
+
chainId: number;
|
|
14
|
+
contracts: {
|
|
15
|
+
escrow: Address;
|
|
16
|
+
registry: Address;
|
|
17
|
+
reputation: Address;
|
|
18
|
+
usdc: Address;
|
|
19
|
+
};
|
|
20
|
+
indexer?: string;
|
|
21
|
+
broker?: string;
|
|
22
|
+
}
|
|
23
|
+
/** Union of all supported chain network configs. */
|
|
24
|
+
export type Network = EVMNetwork;
|
|
25
|
+
/** Parameters for creating a task on any chain. */
|
|
26
|
+
export interface CreateTaskParams {
|
|
27
|
+
taskHash: Hex;
|
|
28
|
+
token: Address | string;
|
|
29
|
+
amount: bigint;
|
|
30
|
+
category: string;
|
|
31
|
+
locationZone: string;
|
|
32
|
+
deadline: bigint;
|
|
33
|
+
/** Per-task verifier address (agent-verification mode). Optional. */
|
|
34
|
+
verifierAgent?: string;
|
|
35
|
+
}
|
|
36
|
+
/** Decoded on-chain task representation (chain-agnostic). */
|
|
37
|
+
export interface DomainTask {
|
|
38
|
+
taskId: TaskId;
|
|
39
|
+
agent: string;
|
|
40
|
+
worker: string;
|
|
41
|
+
token: string;
|
|
42
|
+
amount: bigint;
|
|
43
|
+
taskHash: Hex;
|
|
44
|
+
evidenceHash: Hex;
|
|
45
|
+
status: TaskStatus;
|
|
46
|
+
category: string;
|
|
47
|
+
locationZone: string;
|
|
48
|
+
createdAt: Date;
|
|
49
|
+
deadline: Date;
|
|
50
|
+
}
|
|
51
|
+
/** Task metadata used for discovery / listing. */
|
|
52
|
+
export interface DomainTaskMeta {
|
|
53
|
+
taskId: TaskId;
|
|
54
|
+
agent: string;
|
|
55
|
+
category: string;
|
|
56
|
+
locationZone: string;
|
|
57
|
+
reward: bigint;
|
|
58
|
+
createdAt: Date;
|
|
59
|
+
isOpen: boolean;
|
|
60
|
+
}
|
|
61
|
+
/** On-chain reputation snapshot (chain-agnostic). */
|
|
62
|
+
export interface DomainReputation {
|
|
63
|
+
tasksCompleted: bigint;
|
|
64
|
+
totalScore: bigint;
|
|
65
|
+
disputes: bigint;
|
|
66
|
+
avgScore: number;
|
|
67
|
+
}
|
|
68
|
+
/** Transaction receipt (chain-agnostic). */
|
|
69
|
+
export interface DomainTxReceipt {
|
|
70
|
+
hash: string;
|
|
71
|
+
blockNumber?: number;
|
|
72
|
+
}
|
|
73
|
+
/** Signer abstraction that works across chains. */
|
|
74
|
+
export interface ChainSigner {
|
|
75
|
+
getAddress(): Promise<string>;
|
|
76
|
+
getChainType(): BlockchainType;
|
|
77
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ethers } from 'ethers';
|
|
2
|
+
import { type ChainClientOptions } from '../ChainClient.js';
|
|
3
|
+
import type { CreateTaskParams, DomainReputation, DomainTask, DomainTaskMeta, DomainTxReceipt, EVMNetwork } from '../domain-types.js';
|
|
4
|
+
import type { IBlindMarketChain } from '../IBlindMarketChain.js';
|
|
5
|
+
/**
|
|
6
|
+
* EVM-compatible implementation of IBlindMarketChain.
|
|
7
|
+
*
|
|
8
|
+
* Wraps the existing ChainClient (which bundles BlindEscrowClient,
|
|
9
|
+
* TaskRegistryClient, and BlindReputationClient) and translates domain
|
|
10
|
+
* operations into ethers v6 contract calls on EVM chains (0G, Ethereum, etc.).
|
|
11
|
+
*/
|
|
12
|
+
export declare class EVMChainAdapter implements IBlindMarketChain {
|
|
13
|
+
readonly network: EVMNetwork;
|
|
14
|
+
private client;
|
|
15
|
+
private signer;
|
|
16
|
+
constructor(opts: ChainClientOptions);
|
|
17
|
+
getAddress(): Promise<string>;
|
|
18
|
+
createTask(params: CreateTaskParams): Promise<{
|
|
19
|
+
taskId: bigint;
|
|
20
|
+
receipt: DomainTxReceipt;
|
|
21
|
+
}>;
|
|
22
|
+
assignWorker(taskId: bigint, worker: string): Promise<DomainTxReceipt>;
|
|
23
|
+
submitEvidence(taskId: bigint, evidenceHash: string): Promise<DomainTxReceipt>;
|
|
24
|
+
completeVerification(taskId: bigint, passed: boolean): Promise<DomainTxReceipt>;
|
|
25
|
+
cancelTask(taskId: bigint): Promise<DomainTxReceipt>;
|
|
26
|
+
claimTimeout(taskId: bigint): Promise<DomainTxReceipt>;
|
|
27
|
+
raiseDispute(taskId: bigint): Promise<DomainTxReceipt>;
|
|
28
|
+
resolveDispute(taskId: bigint, workerFavored: boolean): Promise<DomainTxReceipt>;
|
|
29
|
+
getTask(taskId: bigint): Promise<DomainTask>;
|
|
30
|
+
isTaskExpired(taskId: bigint): Promise<boolean>;
|
|
31
|
+
publishTask(taskId: bigint, _meta: Omit<DomainTaskMeta, 'taskId'> & {
|
|
32
|
+
taskId?: bigint;
|
|
33
|
+
}): Promise<DomainTxReceipt>;
|
|
34
|
+
closeTask(taskId: bigint): Promise<DomainTxReceipt>;
|
|
35
|
+
getOpenTasks(offset: bigint, limit: bigint): Promise<DomainTaskMeta[]>;
|
|
36
|
+
openTaskCount(): Promise<bigint>;
|
|
37
|
+
totalTasks(): Promise<bigint>;
|
|
38
|
+
rateWorker(worker: string, score: number, taskId: bigint): Promise<DomainTxReceipt>;
|
|
39
|
+
recordDispute(worker: string, taskId: bigint): Promise<DomainTxReceipt>;
|
|
40
|
+
getReputation(worker: string): Promise<DomainReputation>;
|
|
41
|
+
hasBeenRated(worker: string, taskId: bigint): Promise<boolean>;
|
|
42
|
+
mintAgent(params: {
|
|
43
|
+
to: string;
|
|
44
|
+
encryptedURI: string;
|
|
45
|
+
metadataHash: string;
|
|
46
|
+
}): Promise<{
|
|
47
|
+
tokenId: bigint;
|
|
48
|
+
receipt: DomainTxReceipt;
|
|
49
|
+
}>;
|
|
50
|
+
getEncryptedURI(_tokenId: bigint): Promise<string>;
|
|
51
|
+
getBalance(address: string): Promise<bigint>;
|
|
52
|
+
/** Get the underlying ethers Provider for raw queries. */
|
|
53
|
+
getProvider(): ethers.Provider;
|
|
54
|
+
/** Get the underlying ethers Signer (if configured). */
|
|
55
|
+
getEthersSigner(): ethers.Signer | undefined;
|
|
56
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { ChainClient } from '../ChainClient.js';
|
|
2
|
+
import { resolveNetwork } from '../../network/resolve.js';
|
|
3
|
+
/**
|
|
4
|
+
* EVM-compatible implementation of IBlindMarketChain.
|
|
5
|
+
*
|
|
6
|
+
* Wraps the existing ChainClient (which bundles BlindEscrowClient,
|
|
7
|
+
* TaskRegistryClient, and BlindReputationClient) and translates domain
|
|
8
|
+
* operations into ethers v6 contract calls on EVM chains (0G, Ethereum, etc.).
|
|
9
|
+
*/
|
|
10
|
+
export class EVMChainAdapter {
|
|
11
|
+
network;
|
|
12
|
+
client;
|
|
13
|
+
signer;
|
|
14
|
+
constructor(opts) {
|
|
15
|
+
const resolved = resolveNetwork(opts.network);
|
|
16
|
+
if (resolved.chainType !== 'evm') {
|
|
17
|
+
throw new Error(`EVMChainAdapter requires an EVM network, got ${resolved.chainType}`);
|
|
18
|
+
}
|
|
19
|
+
this.network = resolved;
|
|
20
|
+
this.client = new ChainClient(opts);
|
|
21
|
+
this.signer = opts.signer;
|
|
22
|
+
}
|
|
23
|
+
async getAddress() {
|
|
24
|
+
if (!this.signer)
|
|
25
|
+
throw new Error('No signer configured');
|
|
26
|
+
return this.signer.getAddress();
|
|
27
|
+
}
|
|
28
|
+
// ── Task lifecycle ──────────────────────────────────────────────────────
|
|
29
|
+
async createTask(params) {
|
|
30
|
+
const result = await this.client.escrow.createTask({
|
|
31
|
+
taskHash: params.taskHash,
|
|
32
|
+
token: params.token,
|
|
33
|
+
amount: params.amount,
|
|
34
|
+
category: params.category,
|
|
35
|
+
locationZone: params.locationZone,
|
|
36
|
+
deadline: params.deadline,
|
|
37
|
+
});
|
|
38
|
+
return {
|
|
39
|
+
taskId: result.taskId,
|
|
40
|
+
receipt: {
|
|
41
|
+
hash: result.receipt.hash,
|
|
42
|
+
blockNumber: result.receipt.blockNumber,
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
async assignWorker(taskId, worker) {
|
|
47
|
+
const receipt = await this.client.escrow.assignWorker(taskId, worker);
|
|
48
|
+
return { hash: receipt.hash, blockNumber: receipt.blockNumber };
|
|
49
|
+
}
|
|
50
|
+
async submitEvidence(taskId, evidenceHash) {
|
|
51
|
+
const receipt = await this.client.escrow.submitEvidence(taskId, evidenceHash);
|
|
52
|
+
return { hash: receipt.hash, blockNumber: receipt.blockNumber };
|
|
53
|
+
}
|
|
54
|
+
async completeVerification(taskId, passed) {
|
|
55
|
+
const receipt = await this.client.escrow.completeVerification(taskId, passed);
|
|
56
|
+
return { hash: receipt.hash, blockNumber: receipt.blockNumber };
|
|
57
|
+
}
|
|
58
|
+
async cancelTask(taskId) {
|
|
59
|
+
const receipt = await this.client.escrow.cancelTask(taskId);
|
|
60
|
+
return { hash: receipt.hash, blockNumber: receipt.blockNumber };
|
|
61
|
+
}
|
|
62
|
+
async claimTimeout(taskId) {
|
|
63
|
+
const receipt = await this.client.escrow.claimTimeout(taskId);
|
|
64
|
+
return { hash: receipt.hash, blockNumber: receipt.blockNumber };
|
|
65
|
+
}
|
|
66
|
+
async raiseDispute(taskId) {
|
|
67
|
+
const receipt = await this.client.escrow.raiseDispute(taskId);
|
|
68
|
+
return { hash: receipt.hash, blockNumber: receipt.blockNumber };
|
|
69
|
+
}
|
|
70
|
+
async resolveDispute(taskId, workerFavored) {
|
|
71
|
+
const receipt = await this.client.escrow.resolveDispute(taskId, workerFavored);
|
|
72
|
+
return { hash: receipt.hash, blockNumber: receipt.blockNumber };
|
|
73
|
+
}
|
|
74
|
+
async getTask(taskId) {
|
|
75
|
+
const onChain = await this.client.escrow.getTask(taskId);
|
|
76
|
+
return {
|
|
77
|
+
...onChain,
|
|
78
|
+
category: '', // OnChainTask doesn't decode these contract fields;
|
|
79
|
+
locationZone: '', // they are present in the Solidity Task struct.
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
async isTaskExpired(taskId) {
|
|
83
|
+
return this.client.escrow.isTaskExpired(taskId);
|
|
84
|
+
}
|
|
85
|
+
// ── Task discovery ──────────────────────────────────────────────────────
|
|
86
|
+
async publishTask(taskId, _meta) {
|
|
87
|
+
// The EVM contracts publish tasks via the escrow's TaskCreated event
|
|
88
|
+
// (handled by the backend indexer). This is a no-op at the adapter level
|
|
89
|
+
// for EVM — the registry is updated by the escrow contract internally.
|
|
90
|
+
// Return a stub receipt for interface compatibility.
|
|
91
|
+
return { hash: '0x0', blockNumber: 0 };
|
|
92
|
+
}
|
|
93
|
+
async closeTask(taskId) {
|
|
94
|
+
const receipt = await this.client.registry.closeTask(taskId);
|
|
95
|
+
return { hash: receipt.hash, blockNumber: receipt.blockNumber };
|
|
96
|
+
}
|
|
97
|
+
async getOpenTasks(offset, limit) {
|
|
98
|
+
const taskIds = await this.client.registry.getOpenTasks(offset, limit);
|
|
99
|
+
const metas = await Promise.all(taskIds.map(async (tid) => {
|
|
100
|
+
const meta = await this.client.registry.getTaskMeta(tid);
|
|
101
|
+
return {
|
|
102
|
+
taskId: tid,
|
|
103
|
+
agent: '', // EVM TaskRegistry stores agent; use meta directly
|
|
104
|
+
category: meta.category,
|
|
105
|
+
locationZone: meta.locationZone,
|
|
106
|
+
reward: meta.reward,
|
|
107
|
+
createdAt: meta.createdAt,
|
|
108
|
+
isOpen: true,
|
|
109
|
+
};
|
|
110
|
+
}));
|
|
111
|
+
return metas;
|
|
112
|
+
}
|
|
113
|
+
async openTaskCount() {
|
|
114
|
+
return this.client.registry.openTaskCount();
|
|
115
|
+
}
|
|
116
|
+
async totalTasks() {
|
|
117
|
+
return this.client.registry.totalTasks();
|
|
118
|
+
}
|
|
119
|
+
// ── Reputation ──────────────────────────────────────────────────────────
|
|
120
|
+
async rateWorker(worker, score, taskId) {
|
|
121
|
+
const receipt = await this.client.reputation.rate(worker, score, taskId);
|
|
122
|
+
return { hash: receipt.hash, blockNumber: receipt.blockNumber };
|
|
123
|
+
}
|
|
124
|
+
async recordDispute(worker, taskId) {
|
|
125
|
+
// EVM BlindReputation doesn't expose recordDispute as a standalone client
|
|
126
|
+
// method in the SDK — the escrow calls it internally. For external callers
|
|
127
|
+
// we throw. The escrow contract handles dispute recording via its own path.
|
|
128
|
+
throw new Error('recordDispute is handled internally by BlindEscrow on EVM chains');
|
|
129
|
+
}
|
|
130
|
+
async getReputation(worker) {
|
|
131
|
+
return this.client.reputation.getReputation(worker);
|
|
132
|
+
}
|
|
133
|
+
async hasBeenRated(worker, taskId) {
|
|
134
|
+
return this.client.reputation.hasBeenRated(worker, taskId);
|
|
135
|
+
}
|
|
136
|
+
// ── Agent identity ──────────────────────────────────────────────────────
|
|
137
|
+
async mintAgent(params) {
|
|
138
|
+
// INFT minting is handled by the backend (services/chain.ts → inft.mint()).
|
|
139
|
+
// The SDK doesn't expose a direct INFT client. For direct EVM calls,
|
|
140
|
+
// consumers can use the raw ethers.Contract via the unwrapped signer.
|
|
141
|
+
throw new Error('INFT minting is backend-managed on EVM chains. Use the REST API or raw ethers.Contract.');
|
|
142
|
+
}
|
|
143
|
+
async getEncryptedURI(_tokenId) {
|
|
144
|
+
throw new Error('INFT URI reading is backend-managed on EVM chains. Use the REST API or raw ethers.Contract.');
|
|
145
|
+
}
|
|
146
|
+
// ── Queries ─────────────────────────────────────────────────────────────
|
|
147
|
+
async getBalance(address) {
|
|
148
|
+
return this.client.provider.getBalance(address);
|
|
149
|
+
}
|
|
150
|
+
// ── Accessors for direct ethers access (advanced use) ───────────────────
|
|
151
|
+
/** Get the underlying ethers Provider for raw queries. */
|
|
152
|
+
getProvider() {
|
|
153
|
+
return this.client.provider;
|
|
154
|
+
}
|
|
155
|
+
/** Get the underlying ethers Signer (if configured). */
|
|
156
|
+
getEthersSigner() {
|
|
157
|
+
if (!this.signer)
|
|
158
|
+
return undefined;
|
|
159
|
+
return this.signer.inner;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { EVMChainAdapter } from './EVMChainAdapter.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { EVMChainAdapter } from './EVMChainAdapter.js';
|
package/dist/chain/index.d.ts
CHANGED
|
@@ -4,3 +4,7 @@ export * from './BlindEscrowClient.js';
|
|
|
4
4
|
export * from './TaskRegistryClient.js';
|
|
5
5
|
export * from './BlindReputationClient.js';
|
|
6
6
|
export * from './ChainClient.js';
|
|
7
|
+
export * from './IBlindMarketChain.js';
|
|
8
|
+
export * from './domain-types.js';
|
|
9
|
+
export * from './createChainAdapter.js';
|
|
10
|
+
export * from './evm/index.js';
|
package/dist/chain/index.js
CHANGED
|
@@ -4,3 +4,8 @@ export * from './BlindEscrowClient.js';
|
|
|
4
4
|
export * from './TaskRegistryClient.js';
|
|
5
5
|
export * from './BlindReputationClient.js';
|
|
6
6
|
export * from './ChainClient.js';
|
|
7
|
+
// Chain-agnostic domain interface (EVM only — 0G Chain)
|
|
8
|
+
export * from './IBlindMarketChain.js';
|
|
9
|
+
export * from './domain-types.js';
|
|
10
|
+
export * from './createChainAdapter.js';
|
|
11
|
+
export * from './evm/index.js';
|