@blindmarket/sdk 0.1.7 → 0.4.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/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/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/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 +134 -0
- package/dist/executor/WorkerRuntime.js +277 -0
- package/dist/executor/index.d.ts +1 -0
- package/dist/executor/index.js +1 -0
- package/dist/index.d.ts +82 -9
- package/dist/index.js +60 -6
- 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 +8 -1
- package/biome.json +0 -19
- 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
- package/examples/agent-demo.ts +0 -121
- package/scripts/gen-crypto-fixtures.mjs +0 -72
- package/src/agent/Agent.ts +0 -122
- package/src/agent/index.ts +0 -1
- package/src/chain/BlindEscrowClient.ts +0 -187
- package/src/chain/BlindReputationClient.ts +0 -55
- package/src/chain/ChainClient.ts +0 -59
- package/src/chain/TaskRegistryClient.ts +0 -82
- package/src/chain/abi/BlindEscrow.json +0 -1113
- package/src/chain/abi/BlindReputation.json +0 -447
- package/src/chain/abi/TaskRegistry.json +0 -586
- package/src/chain/abi/index.ts +0 -5
- package/src/chain/errors.ts +0 -43
- package/src/chain/index.ts +0 -6
- package/src/crypto/aes.ts +0 -104
- package/src/crypto/constants.ts +0 -7
- package/src/crypto/ecies.ts +0 -60
- package/src/crypto/envelope.ts +0 -131
- package/src/crypto/hkdf.ts +0 -45
- package/src/crypto/index.ts +0 -6
- package/src/crypto/keys.ts +0 -56
- package/src/errors/BlindMarketError.ts +0 -38
- package/src/errors/codes.ts +0 -67
- package/src/errors/index.ts +0 -3
- package/src/errors/subclasses.ts +0 -59
- package/src/events/EventBus.ts +0 -45
- package/src/events/index.ts +0 -2
- package/src/events/types.ts +0 -13
- package/src/index.ts +0 -617
- package/src/keystore/InMemoryKeyStore.ts +0 -146
- package/src/keystore/KeyStore.ts +0 -19
- package/src/keystore/index.ts +0 -2
- package/src/network/index.ts +0 -3
- package/src/network/presets.ts +0 -27
- package/src/network/resolve.ts +0 -19
- package/src/network/types.ts +0 -18
- package/src/signer/EthersSigner.ts +0 -82
- package/src/signer/PrivateKeySigner.ts +0 -19
- package/src/signer/Signer.ts +0 -40
- package/src/signer/index.ts +0 -3
- package/src/storage/MemoryStorage.ts +0 -49
- package/src/storage/Storage.ts +0 -15
- package/src/storage/ZgStorage.ts +0 -124
- package/src/storage/index.ts +0 -3
- package/src/testing/index.ts +0 -1
- package/src/tools/adapters.ts +0 -177
- package/src/tools/helpers.ts +0 -199
- package/src/tools/index.ts +0 -59
- package/src/tools/types.ts +0 -47
- package/src/types.ts +0 -296
- package/src/verifier/index.ts +0 -1
- package/src/worker/Worker.ts +0 -98
- package/src/worker/index.ts +0 -1
- package/test/agent.test.ts +0 -193
- package/test/chain.test.ts +0 -145
- package/test/crypto.aes.test.ts +0 -81
- package/test/crypto.compat.test.ts +0 -33
- package/test/crypto.ecies.test.ts +0 -64
- package/test/envelope.test.ts +0 -82
- package/test/errors.test.ts +0 -64
- package/test/events.test.ts +0 -59
- package/test/fixtures/crypto.json +0 -16
- package/test/keystore.test.ts +0 -103
- package/test/network.test.ts +0 -53
- package/test/signer.test.ts +0 -66
- package/test/smoke.test.ts +0 -7
- package/test/storage.test.ts +0 -55
- package/test/worker.test.ts +0 -181
- package/tsconfig.build.json +0 -1
- package/tsconfig.json +0 -14
- package/tsup.config.ts +0 -32
- package/vitest.config.ts +0 -17
- /package/{src/api/index.ts → dist/chain/IBlindMarketChain.js} +0 -0
- /package/{src/compute/index.ts → dist/chain/domain-types.js} +0 -0
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import { aesDecrypt, aesEncrypt, generateAesKey, hkdfSha256 } from '../crypto/index.js';
|
|
2
|
-
import { CryptoError } from '../errors/index.js';
|
|
3
|
-
import type { Address, Hex, TaskId, TaskKey, TaskKeyRef } from '../types.js';
|
|
4
|
-
import type { KeyStore } from './KeyStore.js';
|
|
5
|
-
|
|
6
|
-
const EXPORT_FORMAT = 'blindmarket.keystore.v1';
|
|
7
|
-
const EXPORT_INFO = new TextEncoder().encode('BlindMarket-Keystore-Export-v1');
|
|
8
|
-
|
|
9
|
-
interface Entry {
|
|
10
|
-
aesKey: Uint8Array;
|
|
11
|
-
createdAt: number;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
interface ExportShape {
|
|
15
|
-
format: typeof EXPORT_FORMAT;
|
|
16
|
-
salt: string;
|
|
17
|
-
blob: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
interface PlainExport {
|
|
21
|
-
keys: Array<{ taskId: string; aesKey: string; createdAt: number }>;
|
|
22
|
-
peers: Array<{ addr: Address; pubkey: Hex }>;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Default KeyStore. Non-persistent — keys live only for the process lifetime.
|
|
27
|
-
* Export/import is encrypted with a passphrase via HKDF-derived AES-256-GCM,
|
|
28
|
-
* so exported blobs are safe to move between processes.
|
|
29
|
-
*/
|
|
30
|
-
export class InMemoryKeyStore implements KeyStore {
|
|
31
|
-
private readonly keys = new Map<string, Entry>();
|
|
32
|
-
private readonly peers = new Map<Address, Hex>();
|
|
33
|
-
|
|
34
|
-
async putTaskKey(taskId: TaskId, key: TaskKey): Promise<void> {
|
|
35
|
-
this.keys.set(taskId.toString(), {
|
|
36
|
-
aesKey: copy(key.aesKey),
|
|
37
|
-
createdAt: key.createdAt.getTime(),
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async getTaskKey(taskId: TaskId): Promise<TaskKey | null> {
|
|
42
|
-
const e = this.keys.get(taskId.toString());
|
|
43
|
-
if (!e) return null;
|
|
44
|
-
return { aesKey: copy(e.aesKey), createdAt: new Date(e.createdAt) };
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async putPeerPubKey(addr: Address, pubkey: Hex): Promise<void> {
|
|
48
|
-
this.peers.set(addr, pubkey);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async getPeerPubKey(addr: Address): Promise<Hex | null> {
|
|
52
|
-
return this.peers.get(addr) ?? null;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async list(): Promise<TaskKeyRef[]> {
|
|
56
|
-
return Array.from(this.keys.entries()).map(([id, e]) => ({
|
|
57
|
-
taskId: BigInt(id),
|
|
58
|
-
createdAt: new Date(e.createdAt),
|
|
59
|
-
}));
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async delete(taskId: TaskId): Promise<void> {
|
|
63
|
-
this.keys.delete(taskId.toString());
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async export(passphrase: string): Promise<string> {
|
|
67
|
-
if (!passphrase || passphrase.length < 8) {
|
|
68
|
-
throw new CryptoError('CRYPTO/INVALID_KEY', 'passphrase must be ≥8 characters');
|
|
69
|
-
}
|
|
70
|
-
const salt = randomBytes(16);
|
|
71
|
-
const wrapKey = await deriveWrapKey(passphrase, salt);
|
|
72
|
-
const plain: PlainExport = {
|
|
73
|
-
keys: Array.from(this.keys.entries()).map(([taskId, e]) => ({
|
|
74
|
-
taskId,
|
|
75
|
-
aesKey: bytesToHex(e.aesKey),
|
|
76
|
-
createdAt: e.createdAt,
|
|
77
|
-
})),
|
|
78
|
-
peers: Array.from(this.peers.entries()).map(([addr, pubkey]) => ({ addr, pubkey })),
|
|
79
|
-
};
|
|
80
|
-
const blob = await aesEncrypt(new TextEncoder().encode(JSON.stringify(plain)), wrapKey);
|
|
81
|
-
const out: ExportShape = { format: EXPORT_FORMAT, salt: bytesToHex(salt), blob: bytesToHex(blob) };
|
|
82
|
-
return JSON.stringify(out);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
async import(data: string, passphrase: string): Promise<void> {
|
|
86
|
-
let parsed: ExportShape;
|
|
87
|
-
try {
|
|
88
|
-
parsed = JSON.parse(data) as ExportShape;
|
|
89
|
-
} catch (cause) {
|
|
90
|
-
throw new CryptoError('CRYPTO/INTEGRITY_CHECK', 'keystore export is not valid JSON', { cause });
|
|
91
|
-
}
|
|
92
|
-
if (parsed.format !== EXPORT_FORMAT) {
|
|
93
|
-
throw new CryptoError(
|
|
94
|
-
'CRYPTO/UNSUPPORTED_CIPHER',
|
|
95
|
-
`unknown keystore export format: ${parsed.format ?? '(missing)'}`,
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
const salt = hexToBytes(parsed.salt);
|
|
99
|
-
const wrapKey = await deriveWrapKey(passphrase, salt);
|
|
100
|
-
const blob = hexToBytes(parsed.blob);
|
|
101
|
-
const plainBytes = await aesDecrypt(blob, wrapKey);
|
|
102
|
-
const plain = JSON.parse(new TextDecoder().decode(plainBytes)) as PlainExport;
|
|
103
|
-
this.keys.clear();
|
|
104
|
-
this.peers.clear();
|
|
105
|
-
for (const k of plain.keys) {
|
|
106
|
-
this.keys.set(k.taskId, { aesKey: hexToBytes(k.aesKey), createdAt: k.createdAt });
|
|
107
|
-
}
|
|
108
|
-
for (const p of plain.peers) {
|
|
109
|
-
this.peers.set(p.addr, p.pubkey);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function copy(u: Uint8Array): Uint8Array {
|
|
115
|
-
const c = new Uint8Array(u.byteLength);
|
|
116
|
-
c.set(u);
|
|
117
|
-
return c;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function randomBytes(n: number): Uint8Array {
|
|
121
|
-
const c = (globalThis as { crypto: Crypto }).crypto;
|
|
122
|
-
const out = new Uint8Array(n);
|
|
123
|
-
c.getRandomValues(out);
|
|
124
|
-
return out;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
async function deriveWrapKey(passphrase: string, salt: Uint8Array): Promise<Uint8Array> {
|
|
128
|
-
const ikm = new TextEncoder().encode(passphrase);
|
|
129
|
-
return hkdfSha256(ikm, 32, EXPORT_INFO, salt);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function bytesToHex(u: Uint8Array): string {
|
|
133
|
-
return Array.from(u, (b) => b.toString(16).padStart(2, '0')).join('');
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function hexToBytes(hex: string): Uint8Array {
|
|
137
|
-
const out = new Uint8Array(hex.length / 2);
|
|
138
|
-
for (let i = 0; i < out.length; i++) {
|
|
139
|
-
out[i] = Number.parseInt(hex.substring(i * 2, i * 2 + 2), 16);
|
|
140
|
-
}
|
|
141
|
-
return out;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Tree-shakable helper kept here so we don't accidentally ship generateAesKey
|
|
145
|
-
// from this module — it's re-exported from crypto only.
|
|
146
|
-
export { generateAesKey };
|
package/src/keystore/KeyStore.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { Address, Hex, TaskId, TaskKey, TaskKeyRef } from '../types.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Per-session storage for task AES keys and cached peer public keys. The SDK
|
|
5
|
-
* never logs or serializes anything from here — this is the one place at-rest
|
|
6
|
-
* secrets live. Implementations MUST treat passphrase-protected exports as the
|
|
7
|
-
* only portable format.
|
|
8
|
-
*/
|
|
9
|
-
export interface KeyStore {
|
|
10
|
-
putTaskKey(taskId: TaskId, key: TaskKey): Promise<void>;
|
|
11
|
-
getTaskKey(taskId: TaskId): Promise<TaskKey | null>;
|
|
12
|
-
putPeerPubKey(addr: Address, pubkey: Hex): Promise<void>;
|
|
13
|
-
getPeerPubKey(addr: Address): Promise<Hex | null>;
|
|
14
|
-
list(): Promise<TaskKeyRef[]>;
|
|
15
|
-
delete(taskId: TaskId): Promise<void>;
|
|
16
|
-
/** Portable, encrypted-at-rest JSON export for backup/migration. */
|
|
17
|
-
export(passphrase: string): Promise<string>;
|
|
18
|
-
import(data: string, passphrase: string): Promise<void>;
|
|
19
|
-
}
|
package/src/keystore/index.ts
DELETED
package/src/network/index.ts
DELETED
package/src/network/presets.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type { Network } from './types.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Known-good network presets. Addresses pinned per SDK version so upgrading
|
|
5
|
-
* the SDK cannot silently move contracts under a consumer.
|
|
6
|
-
*
|
|
7
|
-
* testnet = 0G Galileo (chainId 16602) — addresses from
|
|
8
|
-
* contracts/deployments/0g-testnet.json (deployed 2026-04-15).
|
|
9
|
-
*/
|
|
10
|
-
export const networks = {
|
|
11
|
-
testnet: {
|
|
12
|
-
name: '0g-galileo-testnet',
|
|
13
|
-
chainId: 16602n,
|
|
14
|
-
rpc: ['https://evmrpc-testnet.0g.ai'],
|
|
15
|
-
contracts: {
|
|
16
|
-
escrow: '0xFd4F93F5A7BE144c405D1D8fbEC63Fb776207681',
|
|
17
|
-
registry: '0xeE52d780A47F77E8a4a1cEb236e3C65A48FbD828',
|
|
18
|
-
reputation: '0x4A6374Fae37E19E69ba43E7cf6994AC15F63256e',
|
|
19
|
-
usdc: '0x317227efcA18D004E12CA8046AEf7E1597458F25',
|
|
20
|
-
},
|
|
21
|
-
indexer: 'https://indexer-storage-testnet-turbo.0g.ai',
|
|
22
|
-
broker: 'https://broker.testnet.0g.ai',
|
|
23
|
-
explorer: 'https://chainscan-galileo.0g.ai',
|
|
24
|
-
},
|
|
25
|
-
} as const satisfies Record<string, Network>;
|
|
26
|
-
|
|
27
|
-
export type NetworkName = keyof typeof networks;
|
package/src/network/resolve.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { ConfigError } from '../errors/index.js';
|
|
2
|
-
import { networks, type NetworkName } from './presets.js';
|
|
3
|
-
import type { Network } from './types.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Resolve a preset name or a literal Network object into the canonical
|
|
7
|
-
* Network used throughout the SDK. Throws ConfigError for unknown names.
|
|
8
|
-
*/
|
|
9
|
-
export function resolveNetwork(arg: NetworkName | Network): Network {
|
|
10
|
-
if (typeof arg === 'string') {
|
|
11
|
-
const preset = (networks as Record<string, Network | undefined>)[arg];
|
|
12
|
-
if (!preset) {
|
|
13
|
-
const known = Object.keys(networks).join(', ');
|
|
14
|
-
throw new ConfigError('CONFIG/INVALID_NETWORK', `unknown network '${arg}' (known: ${known})`);
|
|
15
|
-
}
|
|
16
|
-
return preset;
|
|
17
|
-
}
|
|
18
|
-
return arg;
|
|
19
|
-
}
|
package/src/network/types.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { Address } from '../types.js';
|
|
2
|
-
|
|
3
|
-
export interface NetworkContracts {
|
|
4
|
-
escrow: Address;
|
|
5
|
-
registry: Address;
|
|
6
|
-
reputation: Address;
|
|
7
|
-
usdc: Address;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface Network {
|
|
11
|
-
name: string;
|
|
12
|
-
chainId: bigint;
|
|
13
|
-
rpc: string[];
|
|
14
|
-
contracts: NetworkContracts;
|
|
15
|
-
indexer: string;
|
|
16
|
-
broker: string;
|
|
17
|
-
explorer?: string;
|
|
18
|
-
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { ethers } from 'ethers';
|
|
2
|
-
import { ChainError, ConfigError } from '../errors/index.js';
|
|
3
|
-
import type { Address, Hex } from '../types.js';
|
|
4
|
-
import type { Signer, TxRequest, TypedDataDomain, TypedDataField } from './Signer.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Wraps any ethers v6 Signer. The most common path — accepts ethers.Wallet,
|
|
8
|
-
* ethers.BrowserProvider signer, JsonRpcSigner, etc. Caches the recovered
|
|
9
|
-
* public key after the first successful getPublicKey() call.
|
|
10
|
-
*/
|
|
11
|
-
export class EthersSigner implements Signer {
|
|
12
|
-
private publicKeyCache: Hex | undefined;
|
|
13
|
-
|
|
14
|
-
constructor(private readonly inner: ethers.Signer) {}
|
|
15
|
-
|
|
16
|
-
async getAddress(): Promise<Address> {
|
|
17
|
-
return (await this.inner.getAddress()) as Address;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async chainId(): Promise<bigint> {
|
|
21
|
-
const provider = this.inner.provider;
|
|
22
|
-
if (!provider) {
|
|
23
|
-
throw new ConfigError('CONFIG/BAD_CONFIG', 'signer has no attached provider; cannot read chainId');
|
|
24
|
-
}
|
|
25
|
-
const net = await provider.getNetwork();
|
|
26
|
-
return net.chainId;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async signMessage(msg: string | Uint8Array): Promise<Hex> {
|
|
30
|
-
return (await this.inner.signMessage(msg)) as Hex;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async signTypedData(
|
|
34
|
-
domain: TypedDataDomain,
|
|
35
|
-
types: Record<string, TypedDataField[]>,
|
|
36
|
-
value: Record<string, unknown>,
|
|
37
|
-
): Promise<Hex> {
|
|
38
|
-
return (await this.inner.signTypedData(domain, types, value)) as Hex;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async signTransaction(tx: TxRequest): Promise<Hex> {
|
|
42
|
-
try {
|
|
43
|
-
return (await this.inner.signTransaction({
|
|
44
|
-
to: tx.to,
|
|
45
|
-
...(tx.from !== undefined ? { from: tx.from } : {}),
|
|
46
|
-
...(tx.data !== undefined ? { data: tx.data } : {}),
|
|
47
|
-
...(tx.value !== undefined ? { value: tx.value } : {}),
|
|
48
|
-
...(tx.gasLimit !== undefined ? { gasLimit: tx.gasLimit } : {}),
|
|
49
|
-
...(tx.nonce !== undefined ? { nonce: tx.nonce } : {}),
|
|
50
|
-
...(tx.chainId !== undefined ? { chainId: tx.chainId } : {}),
|
|
51
|
-
})) as Hex;
|
|
52
|
-
} catch (cause) {
|
|
53
|
-
throw new ChainError('CHAIN/TX_REVERTED', 'signTransaction failed', { cause });
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Recovers the uncompressed secp256k1 public key from the signer. For Wallet
|
|
59
|
-
* signers we can read it directly; for generic Signers we sign a canonical
|
|
60
|
-
* probe message once and recover from the signature.
|
|
61
|
-
*/
|
|
62
|
-
async getPublicKey(): Promise<Hex> {
|
|
63
|
-
if (this.publicKeyCache) return this.publicKeyCache;
|
|
64
|
-
|
|
65
|
-
// Fast path: ethers.Wallet exposes signingKey.publicKey directly.
|
|
66
|
-
const maybeWallet = this.inner as unknown as { signingKey?: { publicKey: string } };
|
|
67
|
-
if (maybeWallet.signingKey?.publicKey) {
|
|
68
|
-
this.publicKeyCache = maybeWallet.signingKey.publicKey as Hex;
|
|
69
|
-
return this.publicKeyCache;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Slow path: sign a probe message and recover the public key.
|
|
73
|
-
const probe = 'BlindMarket-PublicKey-Recovery-v1';
|
|
74
|
-
const sig = await this.inner.signMessage(probe);
|
|
75
|
-
const recovered = ethers.SigningKey.recoverPublicKey(
|
|
76
|
-
ethers.hashMessage(probe),
|
|
77
|
-
sig,
|
|
78
|
-
);
|
|
79
|
-
this.publicKeyCache = recovered as Hex;
|
|
80
|
-
return this.publicKeyCache;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { ethers } from 'ethers';
|
|
2
|
-
import { EthersSigner } from './EthersSigner.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Convenience factory for Node / headless agents: builds an EthersSigner
|
|
6
|
-
* backed by a fresh ethers.Wallet from a raw private key (hex, with or
|
|
7
|
-
* without 0x prefix). Optionally attaches an RPC provider so chainId()
|
|
8
|
-
* and on-chain reads work.
|
|
9
|
-
*
|
|
10
|
-
* NEVER pass a private key you don't control — prefer KMS, browser wallet,
|
|
11
|
-
* or hardware signer for production.
|
|
12
|
-
*/
|
|
13
|
-
export class PrivateKeySigner extends EthersSigner {
|
|
14
|
-
constructor(privateKey: string, provider?: ethers.Provider) {
|
|
15
|
-
const pk = privateKey.startsWith('0x') ? privateKey : `0x${privateKey}`;
|
|
16
|
-
const wallet = provider ? new ethers.Wallet(pk, provider) : new ethers.Wallet(pk);
|
|
17
|
-
super(wallet);
|
|
18
|
-
}
|
|
19
|
-
}
|
package/src/signer/Signer.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type { Address, Hex } from '../types.js';
|
|
2
|
-
|
|
3
|
-
export interface TxRequest {
|
|
4
|
-
to: Address;
|
|
5
|
-
from?: Address;
|
|
6
|
-
data?: Hex;
|
|
7
|
-
value?: bigint;
|
|
8
|
-
gasLimit?: bigint;
|
|
9
|
-
nonce?: number;
|
|
10
|
-
chainId?: bigint;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface TypedDataDomain {
|
|
14
|
-
name?: string;
|
|
15
|
-
version?: string;
|
|
16
|
-
chainId?: bigint | number;
|
|
17
|
-
verifyingContract?: Address;
|
|
18
|
-
salt?: Hex;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export type TypedDataField = { name: string; type: string };
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Uniform signing interface used across the SDK. Adapters wrap ethers Signer,
|
|
25
|
-
* raw private keys, EIP-1193 providers, or KMS. Implementations MUST return
|
|
26
|
-
* hex-encoded signatures (0x-prefixed) and addresses (0x-prefixed, 20 bytes).
|
|
27
|
-
*/
|
|
28
|
-
export interface Signer {
|
|
29
|
-
getAddress(): Promise<Address>;
|
|
30
|
-
chainId(): Promise<bigint>;
|
|
31
|
-
signMessage(msg: string | Uint8Array): Promise<Hex>;
|
|
32
|
-
signTypedData(
|
|
33
|
-
domain: TypedDataDomain,
|
|
34
|
-
types: Record<string, TypedDataField[]>,
|
|
35
|
-
value: Record<string, unknown>,
|
|
36
|
-
): Promise<Hex>;
|
|
37
|
-
signTransaction(tx: TxRequest): Promise<Hex>;
|
|
38
|
-
/** Uncompressed secp256k1 public key, 0x04-prefixed (hex). */
|
|
39
|
-
getPublicKey(): Promise<Hex>;
|
|
40
|
-
}
|
package/src/signer/index.ts
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { sha256 } from '../crypto/index.js';
|
|
2
|
-
import { StorageError } from '../errors/index.js';
|
|
3
|
-
import type { RootHash, UploadResult } from '../types.js';
|
|
4
|
-
import type { Storage } from './Storage.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* In-process Storage for tests and local development. Deterministic: rootHash
|
|
8
|
-
* is the SHA-256 of the content (not a merkle root), so the same bytes always
|
|
9
|
-
* produce the same hash. Not for production — no replication, no integrity
|
|
10
|
-
* proofs beyond SHA-256.
|
|
11
|
-
*/
|
|
12
|
-
export class MemoryStorage implements Storage {
|
|
13
|
-
private readonly blobs = new Map<string, Uint8Array>();
|
|
14
|
-
|
|
15
|
-
async upload(bytes: Uint8Array): Promise<UploadResult> {
|
|
16
|
-
const rootHash = await this.hash(bytes);
|
|
17
|
-
this.blobs.set(rootHash, copy(bytes));
|
|
18
|
-
return { rootHash, size: bytes.byteLength };
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
async download(rootHash: RootHash): Promise<Uint8Array> {
|
|
22
|
-
const data = this.blobs.get(rootHash);
|
|
23
|
-
if (!data) {
|
|
24
|
-
throw new StorageError('STORAGE/NOT_FOUND', `no blob at ${rootHash}`);
|
|
25
|
-
}
|
|
26
|
-
return copy(data);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async hash(bytes: Uint8Array): Promise<RootHash> {
|
|
30
|
-
const digest = await sha256(bytes);
|
|
31
|
-
return ('0x' + Array.from(digest, (b) => b.toString(16).padStart(2, '0')).join('')) as RootHash;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/** Test helper: wipe all stored blobs. */
|
|
35
|
-
clear(): void {
|
|
36
|
-
this.blobs.clear();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/** Test helper: count of stored blobs. */
|
|
40
|
-
size(): number {
|
|
41
|
-
return this.blobs.size;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function copy(u: Uint8Array): Uint8Array {
|
|
46
|
-
const c = new Uint8Array(u.byteLength);
|
|
47
|
-
c.set(u);
|
|
48
|
-
return c;
|
|
49
|
-
}
|
package/src/storage/Storage.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { RootHash, UploadResult } from '../types.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Abstraction over blob storage. Default implementation (ZgStorage) uses
|
|
5
|
-
* 0G Storage; MemoryStorage is for tests and local fallback. Consumers can
|
|
6
|
-
* provide their own adapter for IPFS, S3, etc.
|
|
7
|
-
*/
|
|
8
|
-
export interface Storage {
|
|
9
|
-
/** Upload bytes, return root hash + optional tx hash + size. */
|
|
10
|
-
upload(bytes: Uint8Array): Promise<UploadResult>;
|
|
11
|
-
/** Download bytes by root hash. Throws StorageError('STORAGE/NOT_FOUND') if absent. */
|
|
12
|
-
download(rootHash: RootHash): Promise<Uint8Array>;
|
|
13
|
-
/** Compute the canonical root hash without uploading. */
|
|
14
|
-
hash(bytes: Uint8Array): Promise<RootHash>;
|
|
15
|
-
}
|
package/src/storage/ZgStorage.ts
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import { Indexer, MemData } from '@0gfoundation/0g-ts-sdk';
|
|
2
|
-
import type { ethers } from 'ethers';
|
|
3
|
-
import { StorageError } from '../errors/index.js';
|
|
4
|
-
import type { RootHash, UploadResult } from '../types.js';
|
|
5
|
-
import type { Storage } from './Storage.js';
|
|
6
|
-
|
|
7
|
-
export interface ZgStorageOptions {
|
|
8
|
-
/** 0G Storage indexer URL, e.g. 'https://indexer-storage-testnet-turbo.0g.ai'. */
|
|
9
|
-
indexerUrl: string;
|
|
10
|
-
/** 0G chain RPC URL — passed to the indexer for upload fee submission. */
|
|
11
|
-
rpcUrl: string;
|
|
12
|
-
/** Wallet used to pay for uploads. Reads don't require a signer. */
|
|
13
|
-
signer?: ethers.Signer;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Node-only adapter over @0gfoundation/0g-ts-sdk. Browser consumers must
|
|
18
|
-
* provide their own Storage adapter (IPFS, custom server-side proxy, etc.)
|
|
19
|
-
* because the 0G TS SDK uses Node-specific filesystem APIs for downloads.
|
|
20
|
-
*/
|
|
21
|
-
export class ZgStorage implements Storage {
|
|
22
|
-
private readonly indexer: Indexer;
|
|
23
|
-
private readonly opts: ZgStorageOptions;
|
|
24
|
-
|
|
25
|
-
constructor(opts: ZgStorageOptions) {
|
|
26
|
-
this.opts = opts;
|
|
27
|
-
this.indexer = new Indexer(opts.indexerUrl);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async upload(bytes: Uint8Array): Promise<UploadResult> {
|
|
31
|
-
if (!this.opts.signer) {
|
|
32
|
-
throw new StorageError('STORAGE/UPLOAD_FAILED', 'signer required for uploads');
|
|
33
|
-
}
|
|
34
|
-
const memData = new MemData(copy(bytes));
|
|
35
|
-
const [tree, treeErr] = await memData.merkleTree();
|
|
36
|
-
if (treeErr !== null || !tree) {
|
|
37
|
-
throw new StorageError('STORAGE/UPLOAD_FAILED', 'merkle tree computation failed', { cause: treeErr ?? undefined });
|
|
38
|
-
}
|
|
39
|
-
const rootHash = tree.rootHash() as RootHash;
|
|
40
|
-
|
|
41
|
-
let txHash: string | undefined;
|
|
42
|
-
try {
|
|
43
|
-
// The 0G SDK's Signer types are pinned to a specific ethers minor version
|
|
44
|
-
// that may not match the host project's. Runtime is compatible; the cast
|
|
45
|
-
// avoids false-negative type errors across ethers versions.
|
|
46
|
-
// biome-ignore lint/suspicious/noExplicitAny: see comment above
|
|
47
|
-
const [tx, uploadErr] = await this.indexer.upload(memData, this.opts.rpcUrl, this.opts.signer as any);
|
|
48
|
-
if (uploadErr !== null) {
|
|
49
|
-
throw new StorageError('STORAGE/UPLOAD_FAILED', 'indexer upload failed', {
|
|
50
|
-
cause: uploadErr,
|
|
51
|
-
retriable: true,
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
const maybe = tx as { txHash?: string } | null;
|
|
55
|
-
txHash = maybe?.txHash;
|
|
56
|
-
} catch (err) {
|
|
57
|
-
if (err instanceof StorageError) throw err;
|
|
58
|
-
throw new StorageError('STORAGE/UPLOAD_FAILED', 'unexpected upload error', {
|
|
59
|
-
cause: err,
|
|
60
|
-
retriable: true,
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return {
|
|
65
|
-
rootHash,
|
|
66
|
-
...(txHash ? { txHash: txHash as `0x${string}` } : {}),
|
|
67
|
-
size: bytes.byteLength,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
async download(rootHash: RootHash): Promise<Uint8Array> {
|
|
72
|
-
// 0G SDK downloads to a filesystem path. We write to a tmp file, read bytes back,
|
|
73
|
-
// and delete the tmp file regardless of success/failure.
|
|
74
|
-
const [nodeFs, nodePath, nodeOs, nodeCrypto] = await loadNodeFs();
|
|
75
|
-
const rand = nodeCrypto.randomBytes(8).toString('hex');
|
|
76
|
-
const tmp = nodePath.join(nodeOs.tmpdir(), `0g-${rootHash.replace(/^0x/, '')}-${rand}`);
|
|
77
|
-
try {
|
|
78
|
-
const err = await this.indexer.download(rootHash, tmp, true);
|
|
79
|
-
if (err !== null) {
|
|
80
|
-
throw new StorageError('STORAGE/NOT_FOUND', `no blob at ${rootHash}`, {
|
|
81
|
-
cause: err,
|
|
82
|
-
retriable: true,
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
return new Uint8Array(nodeFs.readFileSync(tmp));
|
|
86
|
-
} finally {
|
|
87
|
-
try {
|
|
88
|
-
nodeFs.unlinkSync(tmp);
|
|
89
|
-
} catch {
|
|
90
|
-
// ignore cleanup errors
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
async hash(bytes: Uint8Array): Promise<RootHash> {
|
|
96
|
-
const memData = new MemData(copy(bytes));
|
|
97
|
-
const [tree, err] = await memData.merkleTree();
|
|
98
|
-
if (err !== null || !tree) {
|
|
99
|
-
throw new StorageError('STORAGE/UPLOAD_FAILED', 'merkle tree computation failed', { cause: err ?? undefined });
|
|
100
|
-
}
|
|
101
|
-
return tree.rootHash() as RootHash;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function copy(u: Uint8Array): Uint8Array {
|
|
106
|
-
const c = new Uint8Array(u.byteLength);
|
|
107
|
-
c.set(u);
|
|
108
|
-
return c;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
type NodeFs = { readFileSync: (p: string) => Buffer; unlinkSync: (p: string) => void };
|
|
112
|
-
type NodePath = { join: (...p: string[]) => string };
|
|
113
|
-
type NodeOs = { tmpdir: () => string };
|
|
114
|
-
type NodeCrypto = { randomBytes: (n: number) => { toString: (enc: 'hex') => string } };
|
|
115
|
-
|
|
116
|
-
async function loadNodeFs(): Promise<[NodeFs, NodePath, NodeOs, NodeCrypto]> {
|
|
117
|
-
const [fs, path, os, crypto] = await Promise.all([
|
|
118
|
-
import('node:fs'),
|
|
119
|
-
import('node:path'),
|
|
120
|
-
import('node:os'),
|
|
121
|
-
import('node:crypto'),
|
|
122
|
-
]);
|
|
123
|
-
return [fs as unknown as NodeFs, path as unknown as NodePath, os as unknown as NodeOs, crypto as unknown as NodeCrypto];
|
|
124
|
-
}
|
package/src/storage/index.ts
DELETED
package/src/testing/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|