@orbitmem/sdk 0.1.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.
Files changed (176) hide show
  1. package/README.md +104 -0
  2. package/dist/agent/agent-adapter.d.ts +3 -0
  3. package/dist/agent/agent-adapter.d.ts.map +1 -0
  4. package/dist/agent/agent-adapter.js +3 -0
  5. package/dist/agent/agent-adapter.js.map +1 -0
  6. package/dist/agent/client.d.ts +5 -0
  7. package/dist/agent/client.d.ts.map +1 -0
  8. package/dist/agent/client.js +146 -0
  9. package/dist/agent/client.js.map +1 -0
  10. package/dist/agent/index.d.ts +2 -0
  11. package/dist/agent/index.d.ts.map +1 -0
  12. package/dist/agent/index.js +2 -0
  13. package/dist/agent/index.js.map +1 -0
  14. package/dist/client.d.ts +3 -0
  15. package/dist/client.d.ts.map +1 -0
  16. package/dist/client.js +118 -0
  17. package/dist/client.js.map +1 -0
  18. package/dist/contracts.d.ts +19 -0
  19. package/dist/contracts.d.ts.map +1 -0
  20. package/dist/contracts.js +28 -0
  21. package/dist/contracts.js.map +1 -0
  22. package/dist/data/index.d.ts +5 -0
  23. package/dist/data/index.d.ts.map +1 -0
  24. package/dist/data/index.js +5 -0
  25. package/dist/data/index.js.map +1 -0
  26. package/dist/data/orbitdb.d.ts +10 -0
  27. package/dist/data/orbitdb.d.ts.map +1 -0
  28. package/dist/data/orbitdb.js +39 -0
  29. package/dist/data/orbitdb.js.map +1 -0
  30. package/dist/data/pricing.d.ts +7 -0
  31. package/dist/data/pricing.d.ts.map +1 -0
  32. package/dist/data/pricing.js +55 -0
  33. package/dist/data/pricing.js.map +1 -0
  34. package/dist/data/serialization.d.ts +28 -0
  35. package/dist/data/serialization.d.ts.map +1 -0
  36. package/dist/data/serialization.js +76 -0
  37. package/dist/data/serialization.js.map +1 -0
  38. package/dist/data/vault.d.ts +21 -0
  39. package/dist/data/vault.d.ts.map +1 -0
  40. package/dist/data/vault.js +284 -0
  41. package/dist/data/vault.js.map +1 -0
  42. package/dist/discovery/discovery-layer.d.ts +3 -0
  43. package/dist/discovery/discovery-layer.d.ts.map +1 -0
  44. package/dist/discovery/discovery-layer.js +205 -0
  45. package/dist/discovery/discovery-layer.js.map +1 -0
  46. package/dist/discovery/index.d.ts +4 -0
  47. package/dist/discovery/index.d.ts.map +1 -0
  48. package/dist/discovery/index.js +4 -0
  49. package/dist/discovery/index.js.map +1 -0
  50. package/dist/discovery/mock-registry.d.ts +30 -0
  51. package/dist/discovery/mock-registry.d.ts.map +1 -0
  52. package/dist/discovery/mock-registry.js +71 -0
  53. package/dist/discovery/mock-registry.js.map +1 -0
  54. package/dist/discovery/on-chain-registry.d.ts +35 -0
  55. package/dist/discovery/on-chain-registry.d.ts.map +1 -0
  56. package/dist/discovery/on-chain-registry.js +199 -0
  57. package/dist/discovery/on-chain-registry.js.map +1 -0
  58. package/dist/encryption/aes.d.ts +15 -0
  59. package/dist/encryption/aes.d.ts.map +1 -0
  60. package/dist/encryption/aes.js +63 -0
  61. package/dist/encryption/aes.js.map +1 -0
  62. package/dist/encryption/encryption-layer.d.ts +8 -0
  63. package/dist/encryption/encryption-layer.d.ts.map +1 -0
  64. package/dist/encryption/encryption-layer.js +82 -0
  65. package/dist/encryption/encryption-layer.js.map +1 -0
  66. package/dist/encryption/index.d.ts +6 -0
  67. package/dist/encryption/index.d.ts.map +1 -0
  68. package/dist/encryption/index.js +4 -0
  69. package/dist/encryption/index.js.map +1 -0
  70. package/dist/encryption/lit.d.ts +23 -0
  71. package/dist/encryption/lit.d.ts.map +1 -0
  72. package/dist/encryption/lit.js +113 -0
  73. package/dist/encryption/lit.js.map +1 -0
  74. package/dist/encryption/vault-key.d.ts +37 -0
  75. package/dist/encryption/vault-key.d.ts.map +1 -0
  76. package/dist/encryption/vault-key.js +43 -0
  77. package/dist/encryption/vault-key.js.map +1 -0
  78. package/dist/identity/identity-layer.d.ts +3 -0
  79. package/dist/identity/identity-layer.d.ts.map +1 -0
  80. package/dist/identity/identity-layer.js +99 -0
  81. package/dist/identity/identity-layer.js.map +1 -0
  82. package/dist/identity/index.d.ts +4 -0
  83. package/dist/identity/index.d.ts.map +1 -0
  84. package/dist/identity/index.js +4 -0
  85. package/dist/identity/index.js.map +1 -0
  86. package/dist/identity/ows-adapter.d.ts +15 -0
  87. package/dist/identity/ows-adapter.d.ts.map +1 -0
  88. package/dist/identity/ows-adapter.js +67 -0
  89. package/dist/identity/ows-adapter.js.map +1 -0
  90. package/dist/identity/session.d.ts +10 -0
  91. package/dist/identity/session.d.ts.map +1 -0
  92. package/dist/identity/session.js +36 -0
  93. package/dist/identity/session.js.map +1 -0
  94. package/dist/index.d.ts +12 -0
  95. package/dist/index.d.ts.map +1 -0
  96. package/dist/index.js +12 -0
  97. package/dist/index.js.map +1 -0
  98. package/dist/persistence/create-agent.d.ts +11 -0
  99. package/dist/persistence/create-agent.d.ts.map +1 -0
  100. package/dist/persistence/create-agent.js +47 -0
  101. package/dist/persistence/create-agent.js.map +1 -0
  102. package/dist/persistence/index.d.ts +3 -0
  103. package/dist/persistence/index.d.ts.map +1 -0
  104. package/dist/persistence/index.js +3 -0
  105. package/dist/persistence/index.js.map +1 -0
  106. package/dist/persistence/persistence-layer.d.ts +12 -0
  107. package/dist/persistence/persistence-layer.d.ts.map +1 -0
  108. package/dist/persistence/persistence-layer.js +194 -0
  109. package/dist/persistence/persistence-layer.js.map +1 -0
  110. package/dist/transport/index.d.ts +3 -0
  111. package/dist/transport/index.d.ts.map +1 -0
  112. package/dist/transport/index.js +3 -0
  113. package/dist/transport/index.js.map +1 -0
  114. package/dist/transport/relay-session.d.ts +41 -0
  115. package/dist/transport/relay-session.d.ts.map +1 -0
  116. package/dist/transport/relay-session.js +86 -0
  117. package/dist/transport/relay-session.js.map +1 -0
  118. package/dist/transport/transport-layer.d.ts +32 -0
  119. package/dist/transport/transport-layer.d.ts.map +1 -0
  120. package/dist/transport/transport-layer.js +110 -0
  121. package/dist/transport/transport-layer.js.map +1 -0
  122. package/dist/types.d.ts +1319 -0
  123. package/dist/types.d.ts.map +1 -0
  124. package/dist/types.js +7 -0
  125. package/dist/types.js.map +1 -0
  126. package/package.json +91 -0
  127. package/src/__tests__/client.test.ts +30 -0
  128. package/src/__tests__/orbitdb-availability.ts +8 -0
  129. package/src/agent/__tests__/agent-adapter.test.ts +50 -0
  130. package/src/agent/__tests__/client.test.ts +50 -0
  131. package/src/agent/agent-adapter.ts +2 -0
  132. package/src/agent/client.ts +158 -0
  133. package/src/agent/index.ts +1 -0
  134. package/src/client.ts +134 -0
  135. package/src/contracts.ts +44 -0
  136. package/src/data/__tests__/pricing.test.ts +73 -0
  137. package/src/data/__tests__/vault-encryption.test.ts +346 -0
  138. package/src/data/__tests__/vault.test.ts +75 -0
  139. package/src/data/index.ts +8 -0
  140. package/src/data/orbitdb.ts +47 -0
  141. package/src/data/pricing.ts +63 -0
  142. package/src/data/serialization.ts +108 -0
  143. package/src/data/vault.ts +382 -0
  144. package/src/discovery/__tests__/discovery.test.ts +49 -0
  145. package/src/discovery/__tests__/on-chain-registry.test.ts +176 -0
  146. package/src/discovery/discovery-layer.ts +244 -0
  147. package/src/discovery/index.ts +3 -0
  148. package/src/discovery/mock-registry.ts +96 -0
  149. package/src/discovery/on-chain-registry.ts +237 -0
  150. package/src/encryption/__tests__/aes.test.ts +64 -0
  151. package/src/encryption/__tests__/encryption-layer.test.ts +80 -0
  152. package/src/encryption/__tests__/lit.test.ts +97 -0
  153. package/src/encryption/aes.ts +109 -0
  154. package/src/encryption/encryption-layer.ts +100 -0
  155. package/src/encryption/index.ts +5 -0
  156. package/src/encryption/lit.ts +161 -0
  157. package/src/encryption/vault-key.ts +63 -0
  158. package/src/identity/__tests__/identity.test.ts +31 -0
  159. package/src/identity/__tests__/ows-adapter.test.ts +47 -0
  160. package/src/identity/identity-layer.ts +123 -0
  161. package/src/identity/index.ts +3 -0
  162. package/src/identity/ows-adapter.ts +80 -0
  163. package/src/identity/session.ts +57 -0
  164. package/src/index.ts +12 -0
  165. package/src/persistence/__tests__/create-agent.test.ts +9 -0
  166. package/src/persistence/__tests__/persistence.test.ts +242 -0
  167. package/src/persistence/create-agent.ts +55 -0
  168. package/src/persistence/index.ts +2 -0
  169. package/src/persistence/persistence-layer.ts +236 -0
  170. package/src/transport/__tests__/solana-transport.test.ts +112 -0
  171. package/src/transport/__tests__/transport.test.ts +84 -0
  172. package/src/transport/index.ts +2 -0
  173. package/src/transport/relay-session.ts +118 -0
  174. package/src/transport/transport-layer.ts +171 -0
  175. package/src/types/orbitdb.d.ts +9 -0
  176. package/src/types.ts +1496 -0
@@ -0,0 +1,244 @@
1
+ import type { Address } from "viem";
2
+
3
+ import type { DataRegistration, DiscoveryConfig, IDiscoveryLayer } from "../types.js";
4
+ import { MockRegistry } from "./mock-registry.js";
5
+ import { OnChainRegistry } from "./on-chain-registry.js";
6
+
7
+ export function createDiscoveryLayer(config: DiscoveryConfig): IDiscoveryLayer {
8
+ if (config.publicClient && config.walletClient) {
9
+ return createOnChainDiscoveryLayer(config);
10
+ }
11
+ return createMockDiscoveryLayer(config);
12
+ }
13
+
14
+ // ── On-Chain Implementation ──
15
+
16
+ function createOnChainDiscoveryLayer(config: DiscoveryConfig): IDiscoveryLayer {
17
+ const registry = new OnChainRegistry({
18
+ publicClient: config.publicClient!,
19
+ walletClient: config.walletClient!,
20
+ dataRegistry: config.dataRegistry as Address,
21
+ feedbackRegistry: config.reputationRegistry as Address,
22
+ deployBlock: config.deployBlock,
23
+ });
24
+
25
+ return {
26
+ // ── Data Discovery ──
27
+
28
+ async registerData(opts) {
29
+ // On-chain: mint data NFT with URI containing metadata
30
+ const dataURI = JSON.stringify({
31
+ name: opts.name,
32
+ description: opts.description,
33
+ key: opts.key,
34
+ schema: opts.schema,
35
+ tags: opts.tags,
36
+ });
37
+ const dataId = await registry.registerData(dataURI);
38
+ return {
39
+ dataId,
40
+ dataRegistry: config.dataRegistry,
41
+ vaultAddress: "",
42
+ vaultKey: opts.key,
43
+ name: opts.name,
44
+ description: opts.description,
45
+ visibility: "public",
46
+ schema: opts.schema,
47
+ tags: opts.tags ?? [],
48
+ active: true,
49
+ owner: config.walletClient!.account!.address as any,
50
+ ownerChain: "evm",
51
+ lastUpdated: Date.now(),
52
+ registeredAt: Date.now(),
53
+ };
54
+ },
55
+
56
+ async updateDataRegistration(dataId, updates) {
57
+ if (updates.active !== undefined) {
58
+ await registry.setActive(config.dataRegistry as Address, dataId, updates.active);
59
+ }
60
+ // Re-fetch current state
61
+ const allData = await registry.findData({});
62
+ const match = allData.find((d) => d.dataId === dataId);
63
+ if (!match) throw new Error(`Data registration ${dataId} not found`);
64
+ return { ...match, ...updates, lastUpdated: Date.now() };
65
+ },
66
+
67
+ async findData(query) {
68
+ return registry.findData({ activeOnly: query.verifiedOnly });
69
+ },
70
+
71
+ async getDataScore(_vaultAddress, _path) {
72
+ // On-chain mode requires dataId lookup — return zero score for vault-based lookups
73
+ return {
74
+ dataId: 0,
75
+ vaultAddress: _vaultAddress,
76
+ vaultKey: _path,
77
+ quality: 0,
78
+ freshness: { lastUpdated: 0, score: 0 },
79
+ accuracy: { score: 0, feedbackCount: 0 },
80
+ completeness: { score: 0, feedbackCount: 0 },
81
+ verified: false,
82
+ consumptionCount: 0,
83
+ totalFeedback: 0,
84
+ tagScores: {},
85
+ };
86
+ },
87
+
88
+ async getDataScoreById(dataId) {
89
+ return registry.getDataScore(dataId);
90
+ },
91
+
92
+ async rateData(feedback) {
93
+ return registry.rateData(
94
+ feedback.dataId,
95
+ feedback.value,
96
+ feedback.valueDecimals ?? 0,
97
+ feedback.tag1 ?? "",
98
+ feedback.tag2 ?? "",
99
+ feedback.feedbackURI ?? "",
100
+ "0x0000000000000000000000000000000000000000000000000000000000000000",
101
+ );
102
+ },
103
+
104
+ // ── Validation ──
105
+
106
+ async requestValidation(request) {
107
+ return {
108
+ agentId: request.agentId,
109
+ taskId: request.taskId,
110
+ method: request.method,
111
+ status: "pending" as const,
112
+ };
113
+ },
114
+
115
+ async getValidationStatus(_agentId, _taskId) {
116
+ return null;
117
+ },
118
+
119
+ // ── Lit Protocol Integration ──
120
+
121
+ createDataQualityCondition(opts) {
122
+ return {
123
+ conditionType: "evmContract",
124
+ contractAddress: config.dataRegistry,
125
+ standardContractType: "",
126
+ chain: config.registryChain,
127
+ method: "getScore",
128
+ parameters: [":dataId"],
129
+ returnValueTest: { comparator: ">=", value: String(opts.minQuality) },
130
+ };
131
+ },
132
+ };
133
+ }
134
+
135
+ // ── Mock Implementation (unchanged) ──
136
+
137
+ function createMockDiscoveryLayer(config: DiscoveryConfig): IDiscoveryLayer {
138
+ const registry = new MockRegistry();
139
+ let txCounter = 0;
140
+
141
+ return {
142
+ // ── Data Discovery ──
143
+
144
+ async registerData(opts) {
145
+ return registry.registerData({
146
+ key: opts.key,
147
+ name: opts.name,
148
+ description: opts.description,
149
+ schema: opts.schema,
150
+ tags: opts.tags,
151
+ });
152
+ },
153
+
154
+ async updateDataRegistration(dataId, updates) {
155
+ // Mock: just return the existing registration with updates
156
+ const existing = Array.from((registry as any).data.values()).find(
157
+ (d: any) => d.dataId === dataId,
158
+ ) as DataRegistration | undefined;
159
+ if (!existing) throw new Error(`Data registration ${dataId} not found`);
160
+ Object.assign(existing, updates, { lastUpdated: Date.now() });
161
+ return existing;
162
+ },
163
+
164
+ async findData(query) {
165
+ return registry.findData({
166
+ schema: query.schema,
167
+ tags: query.tags,
168
+ minQuality: query.minQuality,
169
+ verifiedOnly: query.verifiedOnly,
170
+ });
171
+ },
172
+
173
+ async getDataScore(vaultAddress, path) {
174
+ // Find data registration by vault address + path
175
+ const allData = registry.findData({});
176
+ const match = allData.find((d) => d.vaultAddress === vaultAddress && d.vaultKey === path);
177
+ if (!match) {
178
+ return {
179
+ dataId: 0,
180
+ vaultAddress,
181
+ vaultKey: path,
182
+ quality: 0,
183
+ freshness: { lastUpdated: 0, score: 0 },
184
+ accuracy: { score: 0, feedbackCount: 0 },
185
+ completeness: { score: 0, feedbackCount: 0 },
186
+ verified: false,
187
+ consumptionCount: 0,
188
+ totalFeedback: 0,
189
+ tagScores: {},
190
+ };
191
+ }
192
+ return registry.getDataScore(match.dataId);
193
+ },
194
+
195
+ async getDataScoreById(dataId) {
196
+ return registry.getDataScore(dataId);
197
+ },
198
+
199
+ async rateData(feedback) {
200
+ registry.rateData(feedback.dataId, {
201
+ clientAddress: "0x0" as any,
202
+ value: feedback.value,
203
+ valueDecimals: feedback.valueDecimals ?? 0,
204
+ tag1: feedback.tag1,
205
+ tag2: feedback.tag2,
206
+ feedbackURI: feedback.feedbackURI,
207
+ isRevoked: false,
208
+ vaultKey: "",
209
+ qualityDimension: feedback.qualityDimension,
210
+ });
211
+ txCounter++;
212
+ return { txHash: `0xmock_tx_${txCounter}`, feedbackIndex: txCounter };
213
+ },
214
+
215
+ // ── Validation ──
216
+
217
+ async requestValidation(request) {
218
+ return {
219
+ agentId: request.agentId,
220
+ taskId: request.taskId,
221
+ method: request.method,
222
+ status: "pending" as const,
223
+ };
224
+ },
225
+
226
+ async getValidationStatus(_agentId, _taskId) {
227
+ return null;
228
+ },
229
+
230
+ // ── Lit Protocol Integration ──
231
+
232
+ createDataQualityCondition(opts) {
233
+ return {
234
+ conditionType: "evmContract",
235
+ contractAddress: config.dataRegistry,
236
+ standardContractType: "",
237
+ chain: config.registryChain,
238
+ method: "getQualityScore",
239
+ parameters: [":dataId"],
240
+ returnValueTest: { comparator: ">=", value: String(opts.minQuality) },
241
+ };
242
+ },
243
+ };
244
+ }
@@ -0,0 +1,3 @@
1
+ export { createDiscoveryLayer } from "./discovery-layer.js";
2
+ export { MockRegistry } from "./mock-registry.js";
3
+ export { OnChainRegistry, type OnChainRegistryConfig } from "./on-chain-registry.js";
@@ -0,0 +1,96 @@
1
+ import type {
2
+ DataFeedbackEntry,
3
+ DataRegistration,
4
+ DataScore,
5
+ DataTag,
6
+ Visibility,
7
+ WalletAddress,
8
+ } from "../types.js";
9
+
10
+ export class MockRegistry {
11
+ private data = new Map<number, DataRegistration>();
12
+ private dataFeedback = new Map<number, DataFeedbackEntry[]>();
13
+ private nextDataId = 1;
14
+
15
+ registerData(opts: {
16
+ key: string;
17
+ name: string;
18
+ description: string;
19
+ schema?: string;
20
+ tags: DataTag[];
21
+ owner?: WalletAddress;
22
+ ownerChain?: any;
23
+ vaultAddress?: string;
24
+ visibility?: Visibility;
25
+ }): DataRegistration {
26
+ const dataId = this.nextDataId++;
27
+ const reg: DataRegistration = {
28
+ dataId,
29
+ dataRegistry: "mock:0:0xDATA_REG",
30
+ vaultAddress: opts.vaultAddress ?? "",
31
+ vaultKey: opts.key,
32
+ name: opts.name,
33
+ description: opts.description,
34
+ visibility: opts.visibility ?? "public",
35
+ schema: opts.schema,
36
+ tags: opts.tags,
37
+ active: true,
38
+ owner: opts.owner ?? ("0x0" as WalletAddress),
39
+ ownerChain: opts.ownerChain ?? "evm",
40
+ lastUpdated: Date.now(),
41
+ registeredAt: Date.now(),
42
+ };
43
+ this.data.set(dataId, reg);
44
+ return reg;
45
+ }
46
+
47
+ findData(query: {
48
+ schema?: string;
49
+ tags?: DataTag[];
50
+ minQuality?: number;
51
+ verifiedOnly?: boolean;
52
+ }): DataRegistration[] {
53
+ let results = Array.from(this.data.values()).filter((d) => d.active);
54
+ if (query.schema) results = results.filter((d) => d.schema === query.schema);
55
+ if (query.tags?.length)
56
+ results = results.filter((d) => query.tags!.some((t) => d.tags.includes(t)));
57
+ if (query.verifiedOnly) results = results.filter((d) => d.tags.includes("verified"));
58
+ return results;
59
+ }
60
+
61
+ rateData(dataId: number, feedback: DataFeedbackEntry): void {
62
+ const existing = this.dataFeedback.get(dataId) ?? [];
63
+ existing.push(feedback);
64
+ this.dataFeedback.set(dataId, existing);
65
+ }
66
+
67
+ getUserFeedback(address: string): { dataId: number; entry: DataFeedbackEntry }[] {
68
+ const results: { dataId: number; entry: DataFeedbackEntry }[] = [];
69
+ for (const [dataId, entries] of this.dataFeedback.entries()) {
70
+ for (const entry of entries) {
71
+ if (entry.clientAddress === address) results.push({ dataId, entry });
72
+ }
73
+ }
74
+ return results;
75
+ }
76
+
77
+ getDataScore(dataId: number): DataScore {
78
+ const reg = this.data.get(dataId);
79
+ const feedback = this.dataFeedback.get(dataId) ?? [];
80
+ const total = feedback.reduce((sum, f) => sum + f.value, 0);
81
+ const quality = feedback.length > 0 ? Math.round(total / feedback.length) : 0;
82
+ return {
83
+ dataId,
84
+ vaultAddress: reg?.vaultAddress ?? "",
85
+ vaultKey: reg?.vaultKey ?? "",
86
+ quality,
87
+ freshness: { lastUpdated: reg?.lastUpdated ?? 0, score: 100 },
88
+ accuracy: { score: quality, feedbackCount: feedback.length },
89
+ completeness: { score: quality, feedbackCount: feedback.length },
90
+ verified: reg?.tags.includes("verified") ?? false,
91
+ consumptionCount: feedback.length,
92
+ totalFeedback: feedback.length,
93
+ tagScores: {},
94
+ };
95
+ }
96
+ }
@@ -0,0 +1,237 @@
1
+ import { DataRegistryAbi, FeedbackRegistryAbi } from "@orbitmem/contracts";
2
+ import type { Address, Log, PublicClient, WalletClient } from "viem";
3
+ import { parseEventLogs } from "viem";
4
+
5
+ import type { DataRegistration, DataScore, WalletAddress } from "../types.js";
6
+
7
+ export interface OnChainRegistryConfig {
8
+ publicClient: PublicClient;
9
+ walletClient?: WalletClient;
10
+ dataRegistry: Address;
11
+ feedbackRegistry: Address;
12
+ deployBlock?: bigint;
13
+ }
14
+
15
+ export class OnChainRegistry {
16
+ private pub: PublicClient;
17
+ private wallet: WalletClient | undefined;
18
+ private dataReg: Address;
19
+ private feedbackReg: Address;
20
+ private deployBlock: bigint;
21
+
22
+ constructor(config: OnChainRegistryConfig) {
23
+ this.pub = config.publicClient;
24
+ this.wallet = config.walletClient;
25
+ this.dataReg = config.dataRegistry;
26
+ this.feedbackReg = config.feedbackRegistry;
27
+ this.deployBlock = config.deployBlock ?? 0n;
28
+ }
29
+
30
+ private requireWallet(): WalletClient {
31
+ if (!this.wallet) {
32
+ throw new Error("WalletClient is required for write operations");
33
+ }
34
+ return this.wallet;
35
+ }
36
+
37
+ // ── Data Registry ──
38
+
39
+ async registerData(dataURI: string): Promise<number> {
40
+ const wallet = this.requireWallet();
41
+ const hash = await wallet.writeContract({
42
+ address: this.dataReg,
43
+ abi: DataRegistryAbi,
44
+ functionName: "register",
45
+ args: [dataURI],
46
+ chain: wallet.chain,
47
+ account: wallet.account!,
48
+ });
49
+ const receipt = await this.pub.waitForTransactionReceipt({ hash });
50
+ const logs = parseEventLogs({
51
+ abi: DataRegistryAbi,
52
+ logs: receipt.logs as Log[],
53
+ eventName: "DataRegistered",
54
+ });
55
+ return Number(logs[0].args.dataId);
56
+ }
57
+
58
+ async findData(query: { activeOnly?: boolean }): Promise<DataRegistration[]> {
59
+ const latestBlock = await this.pub.getBlockNumber();
60
+ const CHUNK = 1000n;
61
+ const logs: { args: { dataId: bigint; owner: string; dataURI: string } }[] = [];
62
+ for (let from = this.deployBlock; from <= latestBlock; from += CHUNK) {
63
+ const to = from + CHUNK - 1n > latestBlock ? latestBlock : from + CHUNK - 1n;
64
+ const chunk = await this.pub.getContractEvents({
65
+ address: this.dataReg,
66
+ abi: DataRegistryAbi,
67
+ eventName: "DataRegistered",
68
+ fromBlock: from,
69
+ toBlock: to,
70
+ });
71
+ logs.push(...(chunk as unknown as typeof logs));
72
+ }
73
+
74
+ const results: DataRegistration[] = [];
75
+ for (const log of logs) {
76
+ const dataId = Number(log.args.dataId);
77
+ const active = (await this.pub.readContract({
78
+ address: this.dataReg,
79
+ abi: DataRegistryAbi,
80
+ functionName: "isActive",
81
+ args: [BigInt(dataId)],
82
+ })) as boolean;
83
+ if (query.activeOnly && !active) continue;
84
+
85
+ const [owner] = await Promise.all([
86
+ this.pub.readContract({
87
+ address: this.dataReg,
88
+ abi: DataRegistryAbi,
89
+ functionName: "ownerOf",
90
+ args: [BigInt(dataId)],
91
+ }),
92
+ this.pub.readContract({
93
+ address: this.dataReg,
94
+ abi: DataRegistryAbi,
95
+ functionName: "tokenURI",
96
+ args: [BigInt(dataId)],
97
+ }),
98
+ ]);
99
+
100
+ results.push({
101
+ dataId,
102
+ dataRegistry: this.dataReg,
103
+ vaultAddress: "",
104
+ vaultKey: "",
105
+ name: "",
106
+ description: "",
107
+ visibility: "public",
108
+ tags: [],
109
+ active,
110
+ owner: owner as WalletAddress,
111
+ ownerChain: "evm",
112
+ lastUpdated: 0,
113
+ registeredAt: 0,
114
+ });
115
+ }
116
+ return results;
117
+ }
118
+
119
+ async getDataScore(dataId: number): Promise<DataScore> {
120
+ const [totalValue, count] = (await this.pub.readContract({
121
+ address: this.feedbackReg,
122
+ abi: FeedbackRegistryAbi,
123
+ functionName: "getScore",
124
+ args: [this.dataReg, BigInt(dataId)],
125
+ })) as [bigint, bigint];
126
+
127
+ const numCount = Number(count);
128
+ const quality = numCount > 0 ? Math.round(Number(totalValue) / numCount) : 0;
129
+
130
+ return {
131
+ dataId,
132
+ vaultAddress: "",
133
+ vaultKey: "",
134
+ quality,
135
+ freshness: { lastUpdated: 0, score: 0 },
136
+ accuracy: { score: quality, feedbackCount: numCount },
137
+ completeness: { score: quality, feedbackCount: numCount },
138
+ verified: false,
139
+ consumptionCount: numCount,
140
+ totalFeedback: numCount,
141
+ tagScores: {},
142
+ };
143
+ }
144
+
145
+ async getTagScore(
146
+ registryAddr: Address,
147
+ entityId: number,
148
+ tag1: string,
149
+ ): Promise<{ totalValue: number; count: number }> {
150
+ const [totalValue, count] = (await this.pub.readContract({
151
+ address: this.feedbackReg,
152
+ abi: FeedbackRegistryAbi,
153
+ functionName: "getTagScore",
154
+ args: [registryAddr, BigInt(entityId), tag1],
155
+ })) as [bigint, bigint];
156
+ return { totalValue: Number(totalValue), count: Number(count) };
157
+ }
158
+
159
+ async rateData(
160
+ dataId: number,
161
+ value: number,
162
+ valueDecimals: number,
163
+ tag1: string,
164
+ tag2: string,
165
+ feedbackURI: string,
166
+ feedbackHash: `0x${string}`,
167
+ ): Promise<{ txHash: string; feedbackIndex: number }> {
168
+ const wallet = this.requireWallet();
169
+ const hash = await wallet.writeContract({
170
+ address: this.feedbackReg,
171
+ abi: FeedbackRegistryAbi,
172
+ functionName: "giveFeedback",
173
+ args: [
174
+ this.dataReg,
175
+ BigInt(dataId),
176
+ BigInt(value),
177
+ valueDecimals,
178
+ tag1,
179
+ tag2,
180
+ feedbackURI,
181
+ feedbackHash,
182
+ ],
183
+ chain: wallet.chain,
184
+ account: wallet.account!,
185
+ });
186
+ const receipt = await this.pub.waitForTransactionReceipt({ hash });
187
+ const logs = parseEventLogs({
188
+ abi: FeedbackRegistryAbi,
189
+ logs: receipt.logs as Log[],
190
+ eventName: "FeedbackGiven",
191
+ });
192
+ return { txHash: hash, feedbackIndex: logs.length > 0 ? 1 : 0 };
193
+ }
194
+
195
+ async revokeFeedback(registryAddr: Address, entityId: number, index: number): Promise<string> {
196
+ const wallet = this.requireWallet();
197
+ const hash = await wallet.writeContract({
198
+ address: this.feedbackReg,
199
+ abi: FeedbackRegistryAbi,
200
+ functionName: "revokeFeedback",
201
+ args: [registryAddr, BigInt(entityId), BigInt(index)],
202
+ chain: wallet.chain,
203
+ account: wallet.account!,
204
+ });
205
+ await this.pub.waitForTransactionReceipt({ hash });
206
+ return hash;
207
+ }
208
+
209
+ async updateDataURI(dataId: number, dataURI: string): Promise<string> {
210
+ const wallet = this.requireWallet();
211
+ const hash = await wallet.writeContract({
212
+ address: this.dataReg,
213
+ abi: DataRegistryAbi,
214
+ functionName: "setDataURI",
215
+ args: [BigInt(dataId), dataURI],
216
+ chain: wallet.chain,
217
+ account: wallet.account!,
218
+ });
219
+ await this.pub.waitForTransactionReceipt({ hash });
220
+ return hash;
221
+ }
222
+
223
+ async setActive(registryAddr: Address, entityId: number, active: boolean): Promise<string> {
224
+ const wallet = this.requireWallet();
225
+ const abi = DataRegistryAbi;
226
+ const hash = await wallet.writeContract({
227
+ address: registryAddr,
228
+ abi,
229
+ functionName: "setActive",
230
+ args: [BigInt(entityId), active],
231
+ chain: wallet.chain,
232
+ account: wallet.account!,
233
+ });
234
+ await this.pub.waitForTransactionReceipt({ hash });
235
+ return hash;
236
+ }
237
+ }
@@ -0,0 +1,64 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import { AESEngine } from "../aes.js";
4
+
5
+ describe("AESEngine", () => {
6
+ const engine = new AESEngine({ kdf: "hkdf-sha256" });
7
+
8
+ test("deriveKey returns a CryptoKey from wallet signature", async () => {
9
+ const fakeSignature = new Uint8Array(64).fill(1);
10
+ const key = await engine.deriveKey(
11
+ {
12
+ type: "wallet-signature",
13
+ },
14
+ fakeSignature,
15
+ );
16
+ expect(key).toBeDefined();
17
+ expect(key.type).toBe("secret");
18
+ expect(key.algorithm).toMatchObject({ name: "AES-GCM" });
19
+ });
20
+
21
+ test("encrypt then decrypt returns original data", async () => {
22
+ const fakeSignature = new Uint8Array(64).fill(1);
23
+ const key = await engine.deriveKey(
24
+ {
25
+ type: "wallet-signature",
26
+ },
27
+ fakeSignature,
28
+ );
29
+
30
+ const plaintext = new TextEncoder().encode("Hello OrbitMem");
31
+ const encrypted = await engine.encrypt(plaintext, key);
32
+
33
+ expect(encrypted.engine).toBe("aes");
34
+ expect(encrypted.ciphertext).toBeInstanceOf(Uint8Array);
35
+ expect(encrypted.iv).toBeInstanceOf(Uint8Array);
36
+ expect(encrypted.iv.length).toBe(12);
37
+ expect(encrypted.authTag).toBeInstanceOf(Uint8Array);
38
+
39
+ const decrypted = await engine.decrypt(encrypted, key);
40
+ expect(new TextDecoder().decode(decrypted)).toBe("Hello OrbitMem");
41
+ });
42
+
43
+ test("decrypt with wrong key fails", async () => {
44
+ const sig1 = new Uint8Array(64).fill(1);
45
+ const sig2 = new Uint8Array(64).fill(2);
46
+ const key1 = await engine.deriveKey({ type: "wallet-signature" }, sig1);
47
+ const key2 = await engine.deriveKey({ type: "wallet-signature" }, sig2);
48
+
49
+ const plaintext = new TextEncoder().encode("secret");
50
+ const encrypted = await engine.encrypt(plaintext, key1);
51
+
52
+ expect(engine.decrypt(encrypted, key2)).rejects.toThrow();
53
+ });
54
+
55
+ test("encrypt with raw key source", async () => {
56
+ const rawKey = crypto.getRandomValues(new Uint8Array(32));
57
+ const key = await engine.deriveKey({ type: "raw", key: rawKey });
58
+
59
+ const plaintext = new TextEncoder().encode("raw key test");
60
+ const encrypted = await engine.encrypt(plaintext, key);
61
+ const decrypted = await engine.decrypt(encrypted, key);
62
+ expect(new TextDecoder().decode(decrypted)).toBe("raw key test");
63
+ });
64
+ });