nebula-ai-core 0.1.0 → 0.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nebula-ai-core",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "description": "The SDK for nebula, a Mantle-native policy-aware AI treasury assistant: brain, local memory + storage, the policy/approval engine, EOA identity, and the ERC-8004 identity client",
6
6
  "license": "MIT",
@@ -0,0 +1,248 @@
1
+ /**
2
+ * ERC-8004 ("Trustless Agents") Reputation + Validation Registry clients.
3
+ *
4
+ * Thin viem wrappers over `NebulaReputationRegistry` (feedback/scores per agent)
5
+ * and `NebulaValidationRegistry` (request/respond validation), both bound to the
6
+ * Identity Registry. Together with erc8004.ts this is the full 3-registry
7
+ * ERC-8004 surface. Addresses resolve from env → baked-in deployment.
8
+ */
9
+ import type { Address, Hex, PublicClient, WalletClient } from 'viem'
10
+ import type { NebulaNetwork } from '../config'
11
+
12
+ // ─── Reputation ──────────────────────────────────────────────────────────────
13
+ export const REPUTATION_REGISTRY_ABI = [
14
+ {
15
+ type: 'function',
16
+ name: 'giveFeedback',
17
+ stateMutability: 'nonpayable',
18
+ inputs: [
19
+ { name: 'agentId', type: 'uint256' },
20
+ { name: 'score', type: 'uint8' },
21
+ { name: 'tag', type: 'string' },
22
+ { name: 'uri', type: 'string' },
23
+ ],
24
+ outputs: [],
25
+ },
26
+ {
27
+ type: 'function',
28
+ name: 'getReputation',
29
+ stateMutability: 'view',
30
+ inputs: [{ name: 'agentId', type: 'uint256' }],
31
+ outputs: [
32
+ { name: 'count', type: 'uint256' },
33
+ { name: 'averageScore', type: 'uint256' },
34
+ ],
35
+ },
36
+ {
37
+ type: 'function',
38
+ name: 'getFeedback',
39
+ stateMutability: 'view',
40
+ inputs: [
41
+ { name: 'agentId', type: 'uint256' },
42
+ { name: 'index', type: 'uint256' },
43
+ ],
44
+ outputs: [
45
+ { name: 'rater', type: 'address' },
46
+ { name: 'score', type: 'uint8' },
47
+ { name: 'tag', type: 'string' },
48
+ { name: 'uri', type: 'string' },
49
+ { name: 'timestamp', type: 'uint64' },
50
+ ],
51
+ },
52
+ ] as const
53
+
54
+ // ─── Validation ──────────────────────────────────────────────────────────────
55
+ export const VALIDATION_REGISTRY_ABI = [
56
+ {
57
+ type: 'function',
58
+ name: 'requestValidation',
59
+ stateMutability: 'nonpayable',
60
+ inputs: [
61
+ { name: 'agentId', type: 'uint256' },
62
+ { name: 'dataHash', type: 'bytes32' },
63
+ { name: 'uri', type: 'string' },
64
+ ],
65
+ outputs: [{ name: 'requestId', type: 'uint256' }],
66
+ },
67
+ {
68
+ type: 'function',
69
+ name: 'respondValidation',
70
+ stateMutability: 'nonpayable',
71
+ inputs: [
72
+ { name: 'requestId', type: 'uint256' },
73
+ { name: 'passed', type: 'bool' },
74
+ { name: 'score', type: 'uint8' },
75
+ { name: 'uri', type: 'string' },
76
+ ],
77
+ outputs: [],
78
+ },
79
+ {
80
+ type: 'function',
81
+ name: 'getValidation',
82
+ stateMutability: 'view',
83
+ inputs: [{ name: 'requestId', type: 'uint256' }],
84
+ outputs: [
85
+ {
86
+ type: 'tuple',
87
+ components: [
88
+ { name: 'agentId', type: 'uint256' },
89
+ { name: 'requester', type: 'address' },
90
+ { name: 'dataHash', type: 'bytes32' },
91
+ { name: 'requestUri', type: 'string' },
92
+ { name: 'validator', type: 'address' },
93
+ { name: 'responded', type: 'bool' },
94
+ { name: 'passed', type: 'bool' },
95
+ { name: 'score', type: 'uint8' },
96
+ { name: 'responseUri', type: 'string' },
97
+ { name: 'requestedAt', type: 'uint64' },
98
+ { name: 'respondedAt', type: 'uint64' },
99
+ ],
100
+ },
101
+ ],
102
+ },
103
+ {
104
+ type: 'function',
105
+ name: 'totalValidations',
106
+ stateMutability: 'view',
107
+ inputs: [],
108
+ outputs: [{ name: '', type: 'uint256' }],
109
+ },
110
+ ] as const
111
+
112
+ export const NEBULA_REPUTATION_REGISTRY: Partial<Record<NebulaNetwork, Address>> = {
113
+ 'mantle-mainnet': '0x56b11a8f34eCb20899BD4E1eA539E194F007F361',
114
+ 'mantle-testnet': '0x0DA4162BdFaFd0b5a6Da4151E0415aEaBd87B521',
115
+ }
116
+ export const NEBULA_VALIDATION_REGISTRY: Partial<Record<NebulaNetwork, Address>> = {
117
+ 'mantle-mainnet': '0x4A222ec3D7e656ADFE28583219Bed3462973DECD',
118
+ 'mantle-testnet': '0x5eDa2Be8c2c24039952751C817a7E9C8E018628e',
119
+ }
120
+
121
+ export function resolveReputationRegistry(
122
+ network: NebulaNetwork,
123
+ override?: string,
124
+ ): Address | null {
125
+ const c =
126
+ override || process.env.NEBULA_REPUTATION_REGISTRY || NEBULA_REPUTATION_REGISTRY[network]
127
+ return c ? (c as Address) : null
128
+ }
129
+ export function resolveValidationRegistry(
130
+ network: NebulaNetwork,
131
+ override?: string,
132
+ ): Address | null {
133
+ const c =
134
+ override || process.env.NEBULA_VALIDATION_REGISTRY || NEBULA_VALIDATION_REGISTRY[network]
135
+ return c ? (c as Address) : null
136
+ }
137
+
138
+ // ─── Reputation client ──
139
+ export async function giveFeedback(opts: {
140
+ walletClient: WalletClient
141
+ publicClient: PublicClient
142
+ registry: Address
143
+ agentId: bigint
144
+ score: number
145
+ tag: string
146
+ uri: string
147
+ }): Promise<{ txHash: Hex }> {
148
+ const account = opts.walletClient.account
149
+ if (!account) throw new Error('walletClient has no account')
150
+ const { request } = await opts.publicClient.simulateContract({
151
+ address: opts.registry,
152
+ abi: REPUTATION_REGISTRY_ABI,
153
+ functionName: 'giveFeedback',
154
+ args: [opts.agentId, opts.score, opts.tag, opts.uri],
155
+ account,
156
+ })
157
+ const txHash = await opts.walletClient.writeContract(request)
158
+ await opts.publicClient.waitForTransactionReceipt({ hash: txHash })
159
+ return { txHash }
160
+ }
161
+
162
+ export async function getReputation(opts: {
163
+ publicClient: PublicClient
164
+ registry: Address
165
+ agentId: bigint
166
+ }): Promise<{ count: bigint; averageScore: bigint }> {
167
+ const [count, averageScore] = (await opts.publicClient.readContract({
168
+ address: opts.registry,
169
+ abi: REPUTATION_REGISTRY_ABI,
170
+ functionName: 'getReputation',
171
+ args: [opts.agentId],
172
+ })) as [bigint, bigint]
173
+ return { count, averageScore }
174
+ }
175
+
176
+ // ─── Validation client ──
177
+ export async function requestValidation(opts: {
178
+ walletClient: WalletClient
179
+ publicClient: PublicClient
180
+ registry: Address
181
+ agentId: bigint
182
+ dataHash: Hex
183
+ uri: string
184
+ }): Promise<{ requestId: bigint; txHash: Hex }> {
185
+ const account = opts.walletClient.account
186
+ if (!account) throw new Error('walletClient has no account')
187
+ const { request, result } = await opts.publicClient.simulateContract({
188
+ address: opts.registry,
189
+ abi: VALIDATION_REGISTRY_ABI,
190
+ functionName: 'requestValidation',
191
+ args: [opts.agentId, opts.dataHash, opts.uri],
192
+ account,
193
+ })
194
+ const txHash = await opts.walletClient.writeContract(request)
195
+ await opts.publicClient.waitForTransactionReceipt({ hash: txHash })
196
+ return { requestId: result as bigint, txHash }
197
+ }
198
+
199
+ export async function respondValidation(opts: {
200
+ walletClient: WalletClient
201
+ publicClient: PublicClient
202
+ registry: Address
203
+ requestId: bigint
204
+ passed: boolean
205
+ score: number
206
+ uri: string
207
+ }): Promise<{ txHash: Hex }> {
208
+ const account = opts.walletClient.account
209
+ if (!account) throw new Error('walletClient has no account')
210
+ const { request } = await opts.publicClient.simulateContract({
211
+ address: opts.registry,
212
+ abi: VALIDATION_REGISTRY_ABI,
213
+ functionName: 'respondValidation',
214
+ args: [opts.requestId, opts.passed, opts.score, opts.uri],
215
+ account,
216
+ })
217
+ const txHash = await opts.walletClient.writeContract(request)
218
+ await opts.publicClient.waitForTransactionReceipt({ hash: txHash })
219
+ return { txHash }
220
+ }
221
+
222
+ export interface ValidationRecord {
223
+ agentId: bigint
224
+ requester: Address
225
+ dataHash: Hex
226
+ requestUri: string
227
+ validator: Address
228
+ responded: boolean
229
+ passed: boolean
230
+ score: number
231
+ responseUri: string
232
+ requestedAt: bigint
233
+ respondedAt: bigint
234
+ }
235
+
236
+ export async function getValidation(opts: {
237
+ publicClient: PublicClient
238
+ registry: Address
239
+ requestId: bigint
240
+ }): Promise<ValidationRecord> {
241
+ const v = (await opts.publicClient.readContract({
242
+ address: opts.registry,
243
+ abi: VALIDATION_REGISTRY_ABI,
244
+ functionName: 'getValidation',
245
+ args: [opts.requestId],
246
+ })) as ValidationRecord
247
+ return v
248
+ }
@@ -91,6 +91,7 @@ export const IDENTITY_REGISTRY_ABI = [
91
91
  * NEBULA_IDENTITY_REGISTRY. Mainnet pending a funded deploy.
92
92
  */
93
93
  export const NEBULA_IDENTITY_REGISTRY: Partial<Record<NebulaNetwork, Address>> = {
94
+ 'mantle-mainnet': '0x00a818451dC072d449e92a21d02d6B68fc703588',
94
95
  'mantle-testnet': '0x529ae7B0e8A8191c0307b918AA62f1Fc6557a621',
95
96
  }
96
97
 
@@ -27,3 +27,19 @@ export {
27
27
  buildAgentCard,
28
28
  cardToDataUri,
29
29
  } from './agent-card'
30
+
31
+ // ERC-8004 Reputation + Validation registries
32
+ export {
33
+ REPUTATION_REGISTRY_ABI,
34
+ VALIDATION_REGISTRY_ABI,
35
+ NEBULA_REPUTATION_REGISTRY,
36
+ NEBULA_VALIDATION_REGISTRY,
37
+ resolveReputationRegistry,
38
+ resolveValidationRegistry,
39
+ giveFeedback,
40
+ getReputation,
41
+ requestValidation,
42
+ respondValidation,
43
+ getValidation,
44
+ type ValidationRecord,
45
+ } from './erc8004-trust'
package/src/index.ts CHANGED
@@ -225,6 +225,18 @@ export {
225
225
  DEFAULT_AGENT_SKILLS,
226
226
  buildAgentCard,
227
227
  cardToDataUri,
228
+ REPUTATION_REGISTRY_ABI,
229
+ VALIDATION_REGISTRY_ABI,
230
+ NEBULA_REPUTATION_REGISTRY,
231
+ NEBULA_VALIDATION_REGISTRY,
232
+ resolveReputationRegistry,
233
+ resolveValidationRegistry,
234
+ giveFeedback,
235
+ getReputation,
236
+ requestValidation,
237
+ respondValidation,
238
+ getValidation,
239
+ type ValidationRecord,
228
240
  } from './identity'
229
241
 
230
242
  export {