@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
|
@@ -5,8 +5,11 @@ import { wrapChainError } from './errors.js';
|
|
|
5
5
|
|
|
6
6
|
export interface ReputationSnapshot {
|
|
7
7
|
tasksCompleted: bigint;
|
|
8
|
+
/** Raw on-chain value. NOTE: despite the name, the contract returns the
|
|
9
|
+
* average rating already scaled ×100 (450 = 4.50), NOT a cumulative sum. */
|
|
8
10
|
totalScore: bigint;
|
|
9
11
|
disputes: bigint;
|
|
12
|
+
/** 0–5 average rating. */
|
|
10
13
|
avgScore: number;
|
|
11
14
|
}
|
|
12
15
|
|
|
@@ -23,9 +26,11 @@ export class BlindReputationClient {
|
|
|
23
26
|
try {
|
|
24
27
|
const raw = (await this.contract.getReputation!(worker)) as unknown as unknown[];
|
|
25
28
|
const tasksCompleted = BigInt(raw[0] as bigint | number);
|
|
29
|
+
// raw[1] is already avgScore × 100 (contract getReputation returns the
|
|
30
|
+
// average scaled ×100, "450 = 4.50") — divide by 100 only, NOT by tasks.
|
|
26
31
|
const totalScore = BigInt(raw[1] as bigint | number);
|
|
27
32
|
const disputes = BigInt(raw[2] as bigint | number);
|
|
28
|
-
const avgScore =
|
|
33
|
+
const avgScore = Number(totalScore) / 100;
|
|
29
34
|
return { tasksCompleted, totalScore, disputes, avgScore };
|
|
30
35
|
} catch (err) {
|
|
31
36
|
throw wrapChainError(err, 'getReputation');
|
package/src/chain/ChainClient.ts
CHANGED
|
@@ -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';
|
|
@@ -17,15 +18,20 @@ export interface ChainClientOptions {
|
|
|
17
18
|
* ethers runner. Reads use provider (or signer's provider); writes require a
|
|
18
19
|
* signer. To keep the SDK's Signer abstraction decoupled from ethers at the
|
|
19
20
|
* call sites, we unwrap an EthersSigner's inner ethers.Signer lazily here.
|
|
21
|
+
*
|
|
22
|
+
* Only supports EVM networks.
|
|
20
23
|
*/
|
|
21
24
|
export class ChainClient {
|
|
22
25
|
readonly escrow: BlindEscrowClient;
|
|
23
26
|
readonly registry: TaskRegistryClient;
|
|
24
27
|
readonly reputation: BlindReputationClient;
|
|
25
28
|
readonly provider: ethers.Provider;
|
|
26
|
-
readonly network:
|
|
29
|
+
readonly network: EVMNetwork;
|
|
27
30
|
|
|
28
31
|
constructor(opts: ChainClientOptions) {
|
|
32
|
+
if (opts.network.chainType !== 'evm') {
|
|
33
|
+
throw new Error(`ChainClient requires an EVM network, got ${opts.network.chainType}`);
|
|
34
|
+
}
|
|
29
35
|
this.network = opts.network;
|
|
30
36
|
const provider =
|
|
31
37
|
opts.provider ??
|
|
@@ -52,7 +58,7 @@ function unwrapEthersSigner(signer: SdkSigner | undefined): ethers.Signer | unde
|
|
|
52
58
|
return maybe.inner;
|
|
53
59
|
}
|
|
54
60
|
|
|
55
|
-
function defaultProvider(network:
|
|
61
|
+
function defaultProvider(network: EVMNetwork): ethers.Provider {
|
|
56
62
|
const url = network.rpc[0];
|
|
57
63
|
if (!url) throw new Error(`network ${network.name} has no RPC endpoint configured`);
|
|
58
64
|
return new ethers.JsonRpcProvider(url, { chainId: Number(network.chainId), name: network.name });
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CreateTaskParams,
|
|
3
|
+
DomainReputation,
|
|
4
|
+
DomainTask,
|
|
5
|
+
DomainTaskMeta,
|
|
6
|
+
DomainTxReceipt,
|
|
7
|
+
Network,
|
|
8
|
+
} from './domain-types.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Chain-agnostic interface for BlindMarket on-chain operations.
|
|
12
|
+
*
|
|
13
|
+
* Every supported blockchain provides an adapter that implements this interface,
|
|
14
|
+
* translating domain operations into chain-native contract calls. Consumers
|
|
15
|
+
* (backend, agents, CLI) work against this interface and never need to know
|
|
16
|
+
* which chain they're talking to.
|
|
17
|
+
*/
|
|
18
|
+
export interface IBlindMarketChain {
|
|
19
|
+
// ── Chain identity ──────────────────────────────────────────────────────
|
|
20
|
+
|
|
21
|
+
/** The resolved network config this adapter is connected to. */
|
|
22
|
+
readonly network: Network;
|
|
23
|
+
|
|
24
|
+
/** The address of the active signer. */
|
|
25
|
+
getAddress(): Promise<string>;
|
|
26
|
+
|
|
27
|
+
// ── Task lifecycle (BlindEscrow equivalent) ─────────────────────────────
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Create a new task with escrowed funds.
|
|
31
|
+
* Returns the assigned task ID and receipt.
|
|
32
|
+
*/
|
|
33
|
+
createTask(params: CreateTaskParams): Promise<{ taskId: bigint; receipt: DomainTxReceipt }>;
|
|
34
|
+
|
|
35
|
+
/** Assign a worker to a funded task. Caller must be the task agent. */
|
|
36
|
+
assignWorker(taskId: bigint, worker: string): Promise<DomainTxReceipt>;
|
|
37
|
+
|
|
38
|
+
/** Submit an evidence hash for an assigned task. Caller must be the worker. */
|
|
39
|
+
submitEvidence(taskId: bigint, evidenceHash: string): Promise<DomainTxReceipt>;
|
|
40
|
+
|
|
41
|
+
/** Complete verification for a submitted task (called by the verifier). */
|
|
42
|
+
completeVerification(taskId: bigint, passed: boolean): Promise<DomainTxReceipt>;
|
|
43
|
+
|
|
44
|
+
/** Cancel a funded/assigned task and return escrow to the agent. */
|
|
45
|
+
cancelTask(taskId: bigint): Promise<DomainTxReceipt>;
|
|
46
|
+
|
|
47
|
+
/** Claim escrow after timeout expiry (agent-side). */
|
|
48
|
+
claimTimeout(taskId: bigint): Promise<DomainTxReceipt>;
|
|
49
|
+
|
|
50
|
+
/** Raise a dispute on a task. */
|
|
51
|
+
raiseDispute(taskId: bigint): Promise<DomainTxReceipt>;
|
|
52
|
+
|
|
53
|
+
/** Resolve a dispute (admin only). */
|
|
54
|
+
resolveDispute(taskId: bigint, workerFavored: boolean): Promise<DomainTxReceipt>;
|
|
55
|
+
|
|
56
|
+
/** Read full on-chain task state. */
|
|
57
|
+
getTask(taskId: bigint): Promise<DomainTask>;
|
|
58
|
+
|
|
59
|
+
/** Check whether a task's deadline has passed. */
|
|
60
|
+
isTaskExpired(taskId: bigint): Promise<boolean>;
|
|
61
|
+
|
|
62
|
+
// ── Task discovery (TaskRegistry equivalent) ────────────────────────────
|
|
63
|
+
|
|
64
|
+
/** Publish task metadata to the on-chain discovery index. */
|
|
65
|
+
publishTask(taskId: bigint, meta: Omit<DomainTaskMeta, 'taskId'> & { taskId?: bigint }): Promise<DomainTxReceipt>;
|
|
66
|
+
|
|
67
|
+
/** Remove a task from the discovery index (called on assignment/completion). */
|
|
68
|
+
closeTask(taskId: bigint): Promise<DomainTxReceipt>;
|
|
69
|
+
|
|
70
|
+
/** Get a page of open task IDs from the discovery index. */
|
|
71
|
+
getOpenTasks(offset: bigint, limit: bigint): Promise<DomainTaskMeta[]>;
|
|
72
|
+
|
|
73
|
+
/** Count of currently open tasks. */
|
|
74
|
+
openTaskCount(): Promise<bigint>;
|
|
75
|
+
|
|
76
|
+
/** Total tasks ever published. */
|
|
77
|
+
totalTasks(): Promise<bigint>;
|
|
78
|
+
|
|
79
|
+
// ── Reputation (BlindReputation equivalent) ─────────────────────────────
|
|
80
|
+
|
|
81
|
+
/** Rate a worker after task completion (score 1-5). */
|
|
82
|
+
rateWorker(worker: string, score: number, taskId: bigint): Promise<DomainTxReceipt>;
|
|
83
|
+
|
|
84
|
+
/** Record a dispute against a worker. */
|
|
85
|
+
recordDispute(worker: string, taskId: bigint): Promise<DomainTxReceipt>;
|
|
86
|
+
|
|
87
|
+
/** Fetch on-chain reputation for a worker. */
|
|
88
|
+
getReputation(worker: string): Promise<DomainReputation>;
|
|
89
|
+
|
|
90
|
+
/** Check if a worker has already been rated for a given task. */
|
|
91
|
+
hasBeenRated(worker: string, taskId: bigint): Promise<boolean>;
|
|
92
|
+
|
|
93
|
+
// ── Agent identity (INFT equivalent) ────────────────────────────────────
|
|
94
|
+
|
|
95
|
+
/** Mint an agent identity token. Returns the token ID and receipt. */
|
|
96
|
+
mintAgent(params: {
|
|
97
|
+
to: string;
|
|
98
|
+
encryptedURI: string;
|
|
99
|
+
metadataHash: string;
|
|
100
|
+
}): Promise<{ tokenId: bigint; receipt: DomainTxReceipt }>;
|
|
101
|
+
|
|
102
|
+
/** Read the encrypted metadata URI for an agent token. */
|
|
103
|
+
getEncryptedURI(tokenId: bigint): Promise<string>;
|
|
104
|
+
|
|
105
|
+
// ── Queries ──────────────────────────────────────────────────────────────
|
|
106
|
+
|
|
107
|
+
/** Get native balance for an address. */
|
|
108
|
+
getBalance(address: string): Promise<bigint>;
|
|
109
|
+
}
|
|
@@ -5,11 +5,12 @@ import { wrapChainError } from './errors.js';
|
|
|
5
5
|
|
|
6
6
|
export interface OpenTaskMeta {
|
|
7
7
|
taskId: TaskId;
|
|
8
|
-
|
|
8
|
+
agent: Address;
|
|
9
9
|
category: string;
|
|
10
10
|
locationZone: string;
|
|
11
11
|
reward: bigint;
|
|
12
12
|
createdAt: Date;
|
|
13
|
+
isOpen: boolean;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export class TaskRegistryClient {
|
|
@@ -23,14 +24,19 @@ export class TaskRegistryClient {
|
|
|
23
24
|
|
|
24
25
|
async getTaskMeta(taskId: TaskId): Promise<OpenTaskMeta> {
|
|
25
26
|
try {
|
|
27
|
+
// Live TaskMeta struct order: taskId, agent, category, locationZone,
|
|
28
|
+
// reward, createdAt, isOpen (7 fields). The old decode was off by one
|
|
29
|
+
// field from the start (token/agent/category/locationZone), so BigInt() on
|
|
30
|
+
// the locationZone string threw on every real task.
|
|
26
31
|
const raw = (await this.contract.getTaskMeta!(taskId)) as unknown as unknown[];
|
|
27
32
|
return {
|
|
28
33
|
taskId,
|
|
29
|
-
|
|
30
|
-
category: raw[
|
|
31
|
-
locationZone: raw[
|
|
32
|
-
reward: BigInt(raw[
|
|
33
|
-
createdAt: new Date(Number(raw[
|
|
34
|
+
agent: raw[1] as Address,
|
|
35
|
+
category: raw[2] as string,
|
|
36
|
+
locationZone: raw[3] as string,
|
|
37
|
+
reward: BigInt(raw[4] as bigint | number),
|
|
38
|
+
createdAt: new Date(Number(raw[5] as bigint | number) * 1000),
|
|
39
|
+
isOpen: Boolean(raw[6]),
|
|
34
40
|
};
|
|
35
41
|
} catch (err) {
|
|
36
42
|
throw wrapChainError(err, 'getTaskMeta');
|
|
@@ -39,8 +45,11 @@ export class TaskRegistryClient {
|
|
|
39
45
|
|
|
40
46
|
async getOpenTasks(offset: bigint, limit: bigint): Promise<TaskId[]> {
|
|
41
47
|
try {
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
// getOpenTasks returns TaskMeta[] structs, NOT raw ids — extract .taskId
|
|
49
|
+
// (field 0) from each. BigInt()-ing the whole struct tuple threw on any
|
|
50
|
+
// non-empty page.
|
|
51
|
+
const metas = (await this.contract.getOpenTasks!(offset, limit)) as unknown as any[];
|
|
52
|
+
return metas.map((m) => BigInt((m?.taskId ?? m?.[0]) as bigint | number));
|
|
44
53
|
} catch (err) {
|
|
45
54
|
throw wrapChainError(err, 'getOpenTasks');
|
|
46
55
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { IBlindMarketChain } from './IBlindMarketChain.js';
|
|
2
|
+
import { EVMChainAdapter } from './evm/EVMChainAdapter.js';
|
|
3
|
+
import { resolveNetwork } from '../network/resolve.js';
|
|
4
|
+
import type { Network, NetworkName as PresetName } from '../network/index.js';
|
|
5
|
+
import type { EthersSigner } from '../signer/EthersSigner.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Options for creating a chain adapter via the factory.
|
|
9
|
+
*
|
|
10
|
+
* The factory chooses the correct adapter based on `network.chainType`.
|
|
11
|
+
*/
|
|
12
|
+
export interface CreateChainAdapterOptions {
|
|
13
|
+
network: Network | PresetName;
|
|
14
|
+
signer?: EthersSigner;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Factory: create the correct IBlindMarketChain adapter for the given network.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* // EVM (0G)
|
|
23
|
+
* const chain = createChainAdapter({
|
|
24
|
+
* network: 'og-testnet',
|
|
25
|
+
* signer: new PrivateKeySigner(privkey, provider),
|
|
26
|
+
* });
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export function createChainAdapter(opts: CreateChainAdapterOptions): IBlindMarketChain {
|
|
30
|
+
const network = resolveNetwork(opts.network);
|
|
31
|
+
|
|
32
|
+
if (network.chainType !== 'evm') {
|
|
33
|
+
throw new Error(`Unsupported chain type: ${network.chainType}. Only EVM (0G) is supported.`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return new EVMChainAdapter({
|
|
37
|
+
network,
|
|
38
|
+
signer: opts.signer,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { Address, Hex, TaskId, TaskStatus } from '../types.js';
|
|
2
|
+
|
|
3
|
+
// ── Chain-agnostic domain types ───────────────────────────────────────────
|
|
4
|
+
// These types are the BlindMarket domain model, independent of any specific
|
|
5
|
+
// blockchain. Each chain adapter translates between these and its native
|
|
6
|
+
// contract types.
|
|
7
|
+
|
|
8
|
+
export type BlockchainType = 'evm';
|
|
9
|
+
|
|
10
|
+
/** Base fields shared by all chain network configs. */
|
|
11
|
+
export interface NetworkBase {
|
|
12
|
+
name: string;
|
|
13
|
+
chainType: BlockchainType;
|
|
14
|
+
rpc: string[];
|
|
15
|
+
explorer?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** EVM-compatible chain network config (0G, Ethereum, Polygon, etc.). */
|
|
19
|
+
export interface EVMNetwork extends NetworkBase {
|
|
20
|
+
chainType: 'evm';
|
|
21
|
+
chainId: number;
|
|
22
|
+
contracts: {
|
|
23
|
+
escrow: Address;
|
|
24
|
+
registry: Address;
|
|
25
|
+
reputation: Address;
|
|
26
|
+
usdc: Address;
|
|
27
|
+
};
|
|
28
|
+
indexer?: string;
|
|
29
|
+
broker?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Union of all supported chain network configs. */
|
|
33
|
+
export type Network = EVMNetwork;
|
|
34
|
+
|
|
35
|
+
/** Parameters for creating a task on any chain. */
|
|
36
|
+
export interface CreateTaskParams {
|
|
37
|
+
taskHash: Hex;
|
|
38
|
+
token: Address | string;
|
|
39
|
+
amount: bigint;
|
|
40
|
+
category: string;
|
|
41
|
+
locationZone: string;
|
|
42
|
+
deadline: bigint;
|
|
43
|
+
/** Per-task verifier address (agent-verification mode). Optional. */
|
|
44
|
+
verifierAgent?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Decoded on-chain task representation (chain-agnostic). */
|
|
48
|
+
export interface DomainTask {
|
|
49
|
+
taskId: TaskId;
|
|
50
|
+
agent: string;
|
|
51
|
+
worker: string;
|
|
52
|
+
token: string;
|
|
53
|
+
amount: bigint;
|
|
54
|
+
taskHash: Hex;
|
|
55
|
+
evidenceHash: Hex;
|
|
56
|
+
status: TaskStatus;
|
|
57
|
+
category: string;
|
|
58
|
+
locationZone: string;
|
|
59
|
+
createdAt: Date;
|
|
60
|
+
deadline: Date;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Task metadata used for discovery / listing. */
|
|
64
|
+
export interface DomainTaskMeta {
|
|
65
|
+
taskId: TaskId;
|
|
66
|
+
agent: string;
|
|
67
|
+
category: string;
|
|
68
|
+
locationZone: string;
|
|
69
|
+
reward: bigint;
|
|
70
|
+
createdAt: Date;
|
|
71
|
+
isOpen: boolean;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** On-chain reputation snapshot (chain-agnostic). */
|
|
75
|
+
export interface DomainReputation {
|
|
76
|
+
tasksCompleted: bigint;
|
|
77
|
+
totalScore: bigint;
|
|
78
|
+
disputes: bigint;
|
|
79
|
+
avgScore: number;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Transaction receipt (chain-agnostic). */
|
|
83
|
+
export interface DomainTxReceipt {
|
|
84
|
+
hash: string;
|
|
85
|
+
blockNumber?: number;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Signer abstraction that works across chains. */
|
|
89
|
+
export interface ChainSigner {
|
|
90
|
+
getAddress(): Promise<string>;
|
|
91
|
+
getChainType(): BlockchainType;
|
|
92
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { ethers } from 'ethers';
|
|
2
|
+
import type { Address, Hex } from '../../types.js';
|
|
3
|
+
import { ChainClient, type ChainClientOptions } from '../ChainClient.js';
|
|
4
|
+
import { resolveNetwork } from '../../network/resolve.js';
|
|
5
|
+
import type { EthersSigner } from '../../signer/EthersSigner.js';
|
|
6
|
+
import type { Signer } from '../../signer/Signer.js';
|
|
7
|
+
import type {
|
|
8
|
+
CreateTaskParams,
|
|
9
|
+
DomainReputation,
|
|
10
|
+
DomainTask,
|
|
11
|
+
DomainTaskMeta,
|
|
12
|
+
DomainTxReceipt,
|
|
13
|
+
EVMNetwork,
|
|
14
|
+
} from '../domain-types.js';
|
|
15
|
+
import type { IBlindMarketChain } from '../IBlindMarketChain.js';
|
|
16
|
+
import type { OpenTaskMeta } from '../TaskRegistryClient.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* EVM-compatible implementation of IBlindMarketChain.
|
|
20
|
+
*
|
|
21
|
+
* Wraps the existing ChainClient (which bundles BlindEscrowClient,
|
|
22
|
+
* TaskRegistryClient, and BlindReputationClient) and translates domain
|
|
23
|
+
* operations into ethers v6 contract calls on EVM chains (0G, Ethereum, etc.).
|
|
24
|
+
*/
|
|
25
|
+
export class EVMChainAdapter implements IBlindMarketChain {
|
|
26
|
+
readonly network: EVMNetwork;
|
|
27
|
+
private client: ChainClient;
|
|
28
|
+
private signer: EthersSigner | undefined;
|
|
29
|
+
|
|
30
|
+
constructor(opts: ChainClientOptions) {
|
|
31
|
+
const resolved = resolveNetwork(opts.network);
|
|
32
|
+
if (resolved.chainType !== 'evm') {
|
|
33
|
+
throw new Error(`EVMChainAdapter requires an EVM network, got ${resolved.chainType}`);
|
|
34
|
+
}
|
|
35
|
+
this.network = resolved;
|
|
36
|
+
this.client = new ChainClient(opts);
|
|
37
|
+
this.signer = opts.signer as EthersSigner | undefined;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async getAddress(): Promise<string> {
|
|
41
|
+
if (!this.signer) throw new Error('No signer configured');
|
|
42
|
+
return this.signer.getAddress();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ── Task lifecycle ──────────────────────────────────────────────────────
|
|
46
|
+
|
|
47
|
+
async createTask(params: CreateTaskParams): Promise<{ taskId: bigint; receipt: DomainTxReceipt }> {
|
|
48
|
+
const result = await this.client.escrow.createTask({
|
|
49
|
+
taskHash: params.taskHash,
|
|
50
|
+
token: params.token as Address,
|
|
51
|
+
amount: params.amount,
|
|
52
|
+
category: params.category,
|
|
53
|
+
locationZone: params.locationZone,
|
|
54
|
+
deadline: params.deadline,
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
57
|
+
taskId: result.taskId,
|
|
58
|
+
receipt: {
|
|
59
|
+
hash: result.receipt.hash,
|
|
60
|
+
blockNumber: result.receipt.blockNumber,
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async assignWorker(taskId: bigint, worker: string): Promise<DomainTxReceipt> {
|
|
66
|
+
const receipt = await this.client.escrow.assignWorker(taskId, worker as Address);
|
|
67
|
+
return { hash: receipt.hash, blockNumber: receipt.blockNumber };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async submitEvidence(taskId: bigint, evidenceHash: string): Promise<DomainTxReceipt> {
|
|
71
|
+
const receipt = await this.client.escrow.submitEvidence(taskId, evidenceHash as Hex);
|
|
72
|
+
return { hash: receipt.hash, blockNumber: receipt.blockNumber };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async completeVerification(taskId: bigint, passed: boolean): Promise<DomainTxReceipt> {
|
|
76
|
+
const receipt = await this.client.escrow.completeVerification(taskId, passed);
|
|
77
|
+
return { hash: receipt.hash, blockNumber: receipt.blockNumber };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async cancelTask(taskId: bigint): Promise<DomainTxReceipt> {
|
|
81
|
+
const receipt = await this.client.escrow.cancelTask(taskId);
|
|
82
|
+
return { hash: receipt.hash, blockNumber: receipt.blockNumber };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async claimTimeout(taskId: bigint): Promise<DomainTxReceipt> {
|
|
86
|
+
const receipt = await this.client.escrow.claimTimeout(taskId);
|
|
87
|
+
return { hash: receipt.hash, blockNumber: receipt.blockNumber };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async raiseDispute(taskId: bigint): Promise<DomainTxReceipt> {
|
|
91
|
+
const receipt = await this.client.escrow.raiseDispute(taskId);
|
|
92
|
+
return { hash: receipt.hash, blockNumber: receipt.blockNumber };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async resolveDispute(taskId: bigint, workerFavored: boolean): Promise<DomainTxReceipt> {
|
|
96
|
+
const receipt = await this.client.escrow.resolveDispute(taskId, workerFavored);
|
|
97
|
+
return { hash: receipt.hash, blockNumber: receipt.blockNumber };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async getTask(taskId: bigint): Promise<DomainTask> {
|
|
101
|
+
const onChain = await this.client.escrow.getTask(taskId);
|
|
102
|
+
return {
|
|
103
|
+
...onChain,
|
|
104
|
+
category: '', // OnChainTask doesn't decode these contract fields;
|
|
105
|
+
locationZone: '', // they are present in the Solidity Task struct.
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async isTaskExpired(taskId: bigint): Promise<boolean> {
|
|
110
|
+
return this.client.escrow.isTaskExpired(taskId);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ── Task discovery ──────────────────────────────────────────────────────
|
|
114
|
+
|
|
115
|
+
async publishTask(taskId: bigint, _meta: Omit<DomainTaskMeta, 'taskId'> & { taskId?: bigint }): Promise<DomainTxReceipt> {
|
|
116
|
+
// The EVM contracts publish tasks via the escrow's TaskCreated event
|
|
117
|
+
// (handled by the backend indexer). This is a no-op at the adapter level
|
|
118
|
+
// for EVM — the registry is updated by the escrow contract internally.
|
|
119
|
+
// Return a stub receipt for interface compatibility.
|
|
120
|
+
return { hash: '0x0', blockNumber: 0 };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async closeTask(taskId: bigint): Promise<DomainTxReceipt> {
|
|
124
|
+
const receipt = await this.client.registry.closeTask(taskId);
|
|
125
|
+
return { hash: receipt.hash, blockNumber: receipt.blockNumber };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async getOpenTasks(offset: bigint, limit: bigint): Promise<DomainTaskMeta[]> {
|
|
129
|
+
const taskIds = await this.client.registry.getOpenTasks(offset, limit);
|
|
130
|
+
const metas = await Promise.all(
|
|
131
|
+
taskIds.map(async (tid: bigint) => {
|
|
132
|
+
const meta = await this.client.registry.getTaskMeta(tid);
|
|
133
|
+
return {
|
|
134
|
+
taskId: tid,
|
|
135
|
+
agent: '' as Address, // EVM TaskRegistry stores agent; use meta directly
|
|
136
|
+
category: meta.category,
|
|
137
|
+
locationZone: meta.locationZone,
|
|
138
|
+
reward: meta.reward,
|
|
139
|
+
createdAt: meta.createdAt,
|
|
140
|
+
isOpen: true,
|
|
141
|
+
} as DomainTaskMeta;
|
|
142
|
+
}),
|
|
143
|
+
);
|
|
144
|
+
return metas;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async openTaskCount(): Promise<bigint> {
|
|
148
|
+
return this.client.registry.openTaskCount();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async totalTasks(): Promise<bigint> {
|
|
152
|
+
return this.client.registry.totalTasks();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ── Reputation ──────────────────────────────────────────────────────────
|
|
156
|
+
|
|
157
|
+
async rateWorker(worker: string, score: number, taskId: bigint): Promise<DomainTxReceipt> {
|
|
158
|
+
const receipt = await this.client.reputation.rate(worker as Address, score, taskId);
|
|
159
|
+
return { hash: receipt.hash, blockNumber: receipt.blockNumber };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async recordDispute(worker: string, taskId: bigint): Promise<DomainTxReceipt> {
|
|
163
|
+
// EVM BlindReputation doesn't expose recordDispute as a standalone client
|
|
164
|
+
// method in the SDK — the escrow calls it internally. For external callers
|
|
165
|
+
// we throw. The escrow contract handles dispute recording via its own path.
|
|
166
|
+
throw new Error('recordDispute is handled internally by BlindEscrow on EVM chains');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async getReputation(worker: string): Promise<DomainReputation> {
|
|
170
|
+
return this.client.reputation.getReputation(worker as Address);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async hasBeenRated(worker: string, taskId: bigint): Promise<boolean> {
|
|
174
|
+
return this.client.reputation.hasBeenRated(worker as Address, taskId);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ── Agent identity ──────────────────────────────────────────────────────
|
|
178
|
+
|
|
179
|
+
async mintAgent(params: {
|
|
180
|
+
to: string;
|
|
181
|
+
encryptedURI: string;
|
|
182
|
+
metadataHash: string;
|
|
183
|
+
}): Promise<{ tokenId: bigint; receipt: DomainTxReceipt }> {
|
|
184
|
+
// INFT minting is handled by the backend (services/chain.ts → inft.mint()).
|
|
185
|
+
// The SDK doesn't expose a direct INFT client. For direct EVM calls,
|
|
186
|
+
// consumers can use the raw ethers.Contract via the unwrapped signer.
|
|
187
|
+
throw new Error('INFT minting is backend-managed on EVM chains. Use the REST API or raw ethers.Contract.');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async getEncryptedURI(_tokenId: bigint): Promise<string> {
|
|
191
|
+
throw new Error('INFT URI reading is backend-managed on EVM chains. Use the REST API or raw ethers.Contract.');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// ── Queries ─────────────────────────────────────────────────────────────
|
|
195
|
+
|
|
196
|
+
async getBalance(address: string): Promise<bigint> {
|
|
197
|
+
return this.client.provider.getBalance(address);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// ── Accessors for direct ethers access (advanced use) ───────────────────
|
|
201
|
+
|
|
202
|
+
/** Get the underlying ethers Provider for raw queries. */
|
|
203
|
+
getProvider(): ethers.Provider {
|
|
204
|
+
return this.client.provider;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** Get the underlying ethers Signer (if configured). */
|
|
208
|
+
getEthersSigner(): ethers.Signer | undefined {
|
|
209
|
+
if (!this.signer) return undefined;
|
|
210
|
+
return (this.signer as unknown as { inner?: ethers.Signer }).inner;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { EVMChainAdapter } from './EVMChainAdapter.js';
|
package/src/chain/index.ts
CHANGED
|
@@ -4,3 +4,9 @@ export * from './BlindEscrowClient.js';
|
|
|
4
4
|
export * from './TaskRegistryClient.js';
|
|
5
5
|
export * from './BlindReputationClient.js';
|
|
6
6
|
export * from './ChainClient.js';
|
|
7
|
+
|
|
8
|
+
// Chain-agnostic domain interface (EVM only — 0G Chain)
|
|
9
|
+
export * from './IBlindMarketChain.js';
|
|
10
|
+
export * from './domain-types.js';
|
|
11
|
+
export * from './createChainAdapter.js';
|
|
12
|
+
export * from './evm/index.js';
|