8004-solana 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.
Files changed (113) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +418 -0
  3. package/dist/core/agent-mint-resolver.d.ts +62 -0
  4. package/dist/core/agent-mint-resolver.d.ts.map +1 -0
  5. package/dist/core/agent-mint-resolver.js +141 -0
  6. package/dist/core/agent-mint-resolver.js.map +1 -0
  7. package/dist/core/borsh-schemas.d.ts +306 -0
  8. package/dist/core/borsh-schemas.d.ts.map +1 -0
  9. package/dist/core/borsh-schemas.js +552 -0
  10. package/dist/core/borsh-schemas.js.map +1 -0
  11. package/dist/core/client.d.ts +103 -0
  12. package/dist/core/client.d.ts.map +1 -0
  13. package/dist/core/client.js +177 -0
  14. package/dist/core/client.js.map +1 -0
  15. package/dist/core/config-reader.d.ts +19 -0
  16. package/dist/core/config-reader.d.ts.map +1 -0
  17. package/dist/core/config-reader.js +35 -0
  18. package/dist/core/config-reader.js.map +1 -0
  19. package/dist/core/endpoint-crawler.d.ts +44 -0
  20. package/dist/core/endpoint-crawler.d.ts.map +1 -0
  21. package/dist/core/endpoint-crawler.js +280 -0
  22. package/dist/core/endpoint-crawler.js.map +1 -0
  23. package/dist/core/feedback-auth.d.ts +184 -0
  24. package/dist/core/feedback-auth.d.ts.map +1 -0
  25. package/dist/core/feedback-auth.js +232 -0
  26. package/dist/core/feedback-auth.js.map +1 -0
  27. package/dist/core/feedback-manager-solana.d.ts +117 -0
  28. package/dist/core/feedback-manager-solana.d.ts.map +1 -0
  29. package/dist/core/feedback-manager-solana.js +279 -0
  30. package/dist/core/feedback-manager-solana.js.map +1 -0
  31. package/dist/core/instruction-builder.d.ts +122 -0
  32. package/dist/core/instruction-builder.d.ts.map +1 -0
  33. package/dist/core/instruction-builder.js +451 -0
  34. package/dist/core/instruction-builder.js.map +1 -0
  35. package/dist/core/instruction-discriminators.d.ts +84 -0
  36. package/dist/core/instruction-discriminators.d.ts.map +1 -0
  37. package/dist/core/instruction-discriminators.js +102 -0
  38. package/dist/core/instruction-discriminators.js.map +1 -0
  39. package/dist/core/ipfs-client.d.ts +88 -0
  40. package/dist/core/ipfs-client.d.ts.map +1 -0
  41. package/dist/core/ipfs-client.js +321 -0
  42. package/dist/core/ipfs-client.js.map +1 -0
  43. package/dist/core/metaplex-helpers.d.ts +26 -0
  44. package/dist/core/metaplex-helpers.d.ts.map +1 -0
  45. package/dist/core/metaplex-helpers.js +44 -0
  46. package/dist/core/metaplex-helpers.js.map +1 -0
  47. package/dist/core/oasf-validator.d.ts +16 -0
  48. package/dist/core/oasf-validator.d.ts.map +1 -0
  49. package/dist/core/oasf-validator.js +26 -0
  50. package/dist/core/oasf-validator.js.map +1 -0
  51. package/dist/core/pda-helpers.d.ts +102 -0
  52. package/dist/core/pda-helpers.d.ts.map +1 -0
  53. package/dist/core/pda-helpers.js +175 -0
  54. package/dist/core/pda-helpers.js.map +1 -0
  55. package/dist/core/programs.d.ts +100 -0
  56. package/dist/core/programs.d.ts.map +1 -0
  57. package/dist/core/programs.js +108 -0
  58. package/dist/core/programs.js.map +1 -0
  59. package/dist/core/sdk-solana.d.ts +311 -0
  60. package/dist/core/sdk-solana.d.ts.map +1 -0
  61. package/dist/core/sdk-solana.js +597 -0
  62. package/dist/core/sdk-solana.js.map +1 -0
  63. package/dist/core/transaction-builder.d.ts +220 -0
  64. package/dist/core/transaction-builder.d.ts.map +1 -0
  65. package/dist/core/transaction-builder.js +822 -0
  66. package/dist/core/transaction-builder.js.map +1 -0
  67. package/dist/core/utils.d.ts +17 -0
  68. package/dist/core/utils.d.ts.map +1 -0
  69. package/dist/core/utils.js +24 -0
  70. package/dist/core/utils.js.map +1 -0
  71. package/dist/index.d.ts +24 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/dist/index.js +31 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/models/enums.d.ts +23 -0
  76. package/dist/models/enums.d.ts.map +1 -0
  77. package/dist/models/enums.js +25 -0
  78. package/dist/models/enums.js.map +1 -0
  79. package/dist/models/index.d.ts +8 -0
  80. package/dist/models/index.d.ts.map +1 -0
  81. package/dist/models/index.js +8 -0
  82. package/dist/models/index.js.map +1 -0
  83. package/dist/models/interfaces.d.ts +160 -0
  84. package/dist/models/interfaces.d.ts.map +1 -0
  85. package/dist/models/interfaces.js +5 -0
  86. package/dist/models/interfaces.js.map +1 -0
  87. package/dist/models/types.d.ts +11 -0
  88. package/dist/models/types.d.ts.map +1 -0
  89. package/dist/models/types.js +5 -0
  90. package/dist/models/types.js.map +1 -0
  91. package/dist/taxonomies/all_domains.json +1565 -0
  92. package/dist/taxonomies/all_skills.json +1030 -0
  93. package/dist/utils/constants.d.ts +43 -0
  94. package/dist/utils/constants.d.ts.map +1 -0
  95. package/dist/utils/constants.js +51 -0
  96. package/dist/utils/constants.js.map +1 -0
  97. package/dist/utils/id-format.d.ts +30 -0
  98. package/dist/utils/id-format.d.ts.map +1 -0
  99. package/dist/utils/id-format.js +67 -0
  100. package/dist/utils/id-format.js.map +1 -0
  101. package/dist/utils/index.d.ts +8 -0
  102. package/dist/utils/index.d.ts.map +1 -0
  103. package/dist/utils/index.js +8 -0
  104. package/dist/utils/index.js.map +1 -0
  105. package/dist/utils/registration-file-builder.d.ts +15 -0
  106. package/dist/utils/registration-file-builder.d.ts.map +1 -0
  107. package/dist/utils/registration-file-builder.js +54 -0
  108. package/dist/utils/registration-file-builder.js.map +1 -0
  109. package/dist/utils/validation.d.ts +25 -0
  110. package/dist/utils/validation.d.ts.map +1 -0
  111. package/dist/utils/validation.js +61 -0
  112. package/dist/utils/validation.js.map +1 -0
  113. package/package.json +78 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Marco De Rossi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,418 @@
1
+ # 8004-solana
2
+
3
+ > TypeScript SDK for ERC-8004 on Solana
4
+ > Agent identity, reputation and validation standard
5
+
6
+ [![npm](https://img.shields.io/npm/v/8004-solana)](https://www.npmjs.com/package/8004-solana)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+ [![GitHub](https://img.shields.io/badge/GitHub-QuantuLabs%2F8004--solana--ts-blue)](https://github.com/QuantuLabs/8004-solana-ts)
9
+ [![Solana Programs](https://img.shields.io/badge/Programs-8004--solana-purple)](https://github.com/QuantuLabs/8004-solana)
10
+
11
+ > **v0.2.0** - Consolidated program architecture with Metaplex Core
12
+
13
+ ---
14
+
15
+ ## About
16
+
17
+ **8004-solana-ts** is a TypeScript SDK implementing the [ERC-8004 standard](https://eips.ethereum.org/EIPS/eip-8004) on Solana. It provides a seamless way to:
18
+
19
+ - **Register agents as NFTs** on Solana blockchain
20
+ - **Manage agent metadata** and endpoints (MCP, A2A)
21
+ - **Submit and query reputation feedback**
22
+ - **Track agent ownership** and transfers
23
+ - **OASF taxonomies** support (skills & domains)
24
+
25
+ Built with compatibility in mind - API aligned with the reference [agent0-ts SDK](https://github.com/agent0lab/agent0-ts).
26
+
27
+ ---
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ npm install 8004-solana
33
+ # or
34
+ yarn add 8004-solana
35
+ # or
36
+ pnpm add 8004-solana
37
+ ```
38
+
39
+ ### Or install from GitHub
40
+
41
+ ```bash
42
+ npm install github:QuantuLabs/8004-solana-ts
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Quick Start
48
+
49
+ ```typescript
50
+ import { SolanaSDK } from '8004-solana';
51
+ import { Keypair } from '@solana/web3.js';
52
+
53
+ // 1. Setup SDK with signer
54
+ const signer = Keypair.fromSecretKey(Uint8Array.from(JSON.parse(process.env.SOLANA_PRIVATE_KEY!)));
55
+ const sdk = new SolanaSDK({ signer });
56
+
57
+ // 2. Register a new agent
58
+ const registration = await sdk.registerAgent('ipfs://QmAgentMetadata');
59
+ const agentId = registration.agentId!;
60
+ console.log(`✓ Agent #${agentId} registered`);
61
+
62
+ // 3. Set on-chain metadata (optional)
63
+ await sdk.setMetadata(agentId, 'version', '1.0.0');
64
+ await sdk.setMetadata(agentId, 'certification', 'verified', true); // immutable
65
+ console.log('✓ On-chain metadata set');
66
+
67
+ // 4. Load agent data
68
+ const agent = await sdk.loadAgent(agentId);
69
+ console.log(`Agent: ${agent?.nft_name}, Owner: ${agent?.getOwnerPublicKey().toBase58()}`);
70
+
71
+ // 5. Give feedback (from another user)
72
+ await sdk.giveFeedback(agentId, {
73
+ score: 85,
74
+ tag1: 'helpful',
75
+ tag2: 'accurate',
76
+ fileUri: 'ipfs://QmFeedbackDetails',
77
+ fileHash: Buffer.alloc(32),
78
+ });
79
+ console.log('✓ Feedback submitted');
80
+
81
+ // 6. Get reputation summary
82
+ const summary = await sdk.getReputationSummary(agentId);
83
+ console.log(`Score: ${summary.averageScore}/100 (${summary.count} reviews)`);
84
+
85
+ // 7. Transfer agent (optional)
86
+ // await sdk.transferAgent(agentId, newOwnerPublicKey);
87
+ ```
88
+
89
+ > **Note**: For advanced queries like `getAgentsByOwner()`, a custom RPC provider is recommended.
90
+ > Free tiers are available - see [RPC Provider Recommendations](#rpc-provider-recommendations).
91
+
92
+ 📁 **More examples**: See the [`examples/`](#examples) directory for complete usage patterns.
93
+
94
+ ---
95
+
96
+ ## SolanaSDK API Reference
97
+
98
+ ### Constructor
99
+
100
+ ```typescript
101
+ import { SolanaSDK } from '8004-solana';
102
+ import { Keypair } from '@solana/web3.js';
103
+
104
+ // Default: devnet, read-only
105
+ const sdk = new SolanaSDK();
106
+
107
+ // With signer (for write operations)
108
+ const sdk = new SolanaSDK({ signer: Keypair.generate() });
109
+
110
+ // Custom RPC (for advanced queries)
111
+ const sdk = new SolanaSDK({ rpcUrl: 'https://your-rpc.helius.dev' });
112
+
113
+ // Full config
114
+ const sdk = new SolanaSDK({
115
+ cluster: 'devnet', // 'devnet' | 'mainnet-beta' (default: 'devnet')
116
+ rpcUrl: 'https://...', // Optional custom RPC
117
+ signer: keypair, // Optional signer for write operations
118
+ });
119
+ ```
120
+
121
+ ### Utility Methods
122
+
123
+ | Method | Return Type | Description |
124
+ |--------|-------------|-------------|
125
+ | `isReadOnly` | `boolean` | True if SDK has no signer |
126
+ | `canWrite` | `boolean` | True if SDK can perform write operations |
127
+ | `chainId()` | `Promise<string>` | Returns `solana-{cluster}` (e.g., `solana-devnet`) |
128
+ | `getCluster()` | `Cluster` | Returns current cluster name |
129
+ | `registries()` | `Record<string, string>` | Returns program IDs (`IDENTITY`, `REPUTATION`, `VALIDATION`) |
130
+ | `getProgramIds()` | `object` | Returns program IDs as PublicKey objects |
131
+ | `getRpcUrl()` | `string` | Returns current RPC URL |
132
+ | `supportsAdvancedQueries()` | `boolean` | True if RPC supports getProgramAccounts with memcmp |
133
+
134
+ ### Agent Read Methods
135
+
136
+ | Method | Signature | Description |
137
+ |--------|-----------|-------------|
138
+ | `loadAgent` | `(agentId: number \| bigint) => Promise<AgentAccount \| null>` | Load agent data from chain |
139
+ | `getAgent` | `(agentId: number \| bigint) => Promise<AgentAccount \| null>` | Alias for loadAgent |
140
+ | `agentExists` | `(agentId: number \| bigint) => Promise<boolean>` | Check if agent exists |
141
+ | `getAgentOwner` | `(agentId: number \| bigint) => Promise<PublicKey \| null>` | Get agent owner |
142
+ | `isAgentOwner` | `(agentId, address) => Promise<boolean>` | Check if address owns agent |
143
+
144
+ ### Agent Write Methods
145
+
146
+ | Method | Signature | Description |
147
+ |--------|-----------|-------------|
148
+ | `registerAgent` | `(tokenUri?, metadata?) => Promise<TransactionResult>` | Register new agent |
149
+ | `transferAgent` | `(agentId, newOwner) => Promise<TransactionResult>` | Transfer agent ownership |
150
+ | `setAgentUri` | `(agentId, newUri) => Promise<TransactionResult>` | Update agent URI |
151
+ | `setMetadata` | `(agentId, key, value, immutable?) => Promise<TransactionResult>` | Set on-chain metadata (optional, PDA-based) |
152
+
153
+ **On-chain Metadata (v0.2.0, optional):**
154
+
155
+ Store arbitrary key-value pairs directly on-chain. This is optional - most agent data should be in the IPFS registration file.
156
+
157
+ ```typescript
158
+ // Set mutable on-chain metadata (default)
159
+ await sdk.setMetadata(agentId, 'version', '1.0.0');
160
+
161
+ // Set immutable on-chain metadata (cannot be modified or deleted)
162
+ await sdk.setMetadata(agentId, 'certification', 'verified', true);
163
+ ```
164
+
165
+ ### Reputation Methods
166
+
167
+ | Method | Signature | Description |
168
+ |--------|-----------|-------------|
169
+ | `getSummary` | `(agentId, minScore?, clientFilter?) => Promise<ReputationSummary>` | Get full reputation summary |
170
+ | `getReputationSummary` | `(agentId) => Promise<{count, averageScore}>` | Get simplified reputation stats |
171
+ | `giveFeedback` | `(agentId, feedbackFile) => Promise<TransactionResult>` | Submit feedback |
172
+ | `getFeedback` | `(agentId, client, index) => Promise<Feedback \| null>` | Read specific feedback |
173
+ | `readFeedback` | `(agentId, client, index) => Promise<Feedback \| null>` | Alias for getFeedback |
174
+ | `revokeFeedback` | `(agentId, index) => Promise<TransactionResult>` | Revoke submitted feedback |
175
+ | `getLastIndex` | `(agentId, client) => Promise<bigint>` | Get last feedback index |
176
+ | `appendResponse` | `(agentId, client, index, uri, hash) => Promise<TransactionResult>` | Add response to feedback |
177
+
178
+ ### Validation Methods
179
+
180
+ | Method | Signature | Description |
181
+ |--------|-----------|-------------|
182
+ | `requestValidation` | `(agentId, validator, methodId, uri, hash) => Promise<TransactionResult>` | Request validation |
183
+ | `respondToValidation` | `(agentId, requestIndex, score, uri, hash, status) => Promise<TransactionResult>` | Respond to validation |
184
+
185
+ ### Advanced Queries (Requires Custom RPC)
186
+
187
+ These methods require a custom RPC provider (Helius, Triton, etc.) that supports `getProgramAccounts`:
188
+
189
+ | Method | Signature | Description |
190
+ |--------|-----------|-------------|
191
+ | `getAgentsByOwner` | `(owner: PublicKey) => Promise<AgentAccount[]>` | Get all agents owned by address |
192
+ | `readAllFeedback` | `(agentId, includeRevoked?) => Promise<Feedback[]>` | Get all feedback for agent |
193
+ | `getClients` | `(agentId) => Promise<PublicKey[]>` | Get all clients who gave feedback |
194
+
195
+ ---
196
+
197
+ ## Architecture
198
+
199
+ Built on a consolidated Solana program implementing ERC-8004:
200
+
201
+ | Program | Program ID | Description |
202
+ |---------|------------|-------------|
203
+ | **AgentRegistry8004** | `HvF3JqhahcX7JfhbDRYYCJ7S3f6nJdrqu5yi9shyTREp` | Identity, Reputation & Validation (consolidated) |
204
+
205
+ **v0.2.0 Changes:**
206
+ - Single consolidated program (was 3 separate programs)
207
+ - Uses **Metaplex Core** for NFTs (was Token Metadata)
208
+ - Global feedback index (was per-client)
209
+ - 89 tests passing on devnet
210
+
211
+ ---
212
+
213
+ ## RPC Provider Recommendations
214
+
215
+ The default Solana devnet RPC works for basic operations but has rate limits.
216
+ For **production use** or **advanced queries** (like `getProgramAccounts`), use a custom RPC provider.
217
+
218
+ **Good news**: Free tiers are sufficient for most use cases!
219
+
220
+ | Provider | Free Tier | Features | Signup |
221
+ |----------|-----------|----------|--------|
222
+ | **Helius** | 100k req/month | Full devnet support, getProgramAccounts | https://helius.dev |
223
+ | **QuickNode** | 10M credits/month | Multi-chain support | https://quicknode.com |
224
+ | **Alchemy** | 300M CU/month | WebSockets, enhanced APIs | https://alchemy.com |
225
+ | **Triton** | Free tier available | Solana-focused | https://triton.one |
226
+
227
+ ### When do you need a custom RPC?
228
+
229
+ | Operation | Default RPC | Custom RPC |
230
+ |-----------|-------------|------------|
231
+ | `loadAgent()` | Works | Works |
232
+ | `giveFeedback()` | Works | Works |
233
+ | `getSummary()` | Works | Works |
234
+ | `getAgentsByOwner()` | **Fails** | Works |
235
+ | `readAllFeedback()` | **Fails** | Works |
236
+ | `getClients()` | **Fails** | Works |
237
+
238
+ **Recommendation**: Start with default RPC. Switch to Helius free tier when you need advanced queries.
239
+
240
+ ```typescript
241
+ const sdk = new SolanaSDK({
242
+ rpcUrl: 'https://your-helius-rpc.helius.dev',
243
+ signer: yourKeypair,
244
+ });
245
+
246
+ // Now advanced queries work
247
+ const agents = await sdk.getAgentsByOwner(ownerPublicKey);
248
+ ```
249
+
250
+ ---
251
+
252
+ ## Development
253
+
254
+ ```bash
255
+ # Clone repository
256
+ git clone https://github.com/QuantuLabs/8004-solana-ts.git
257
+ cd 8004-solana-ts
258
+
259
+ # Install dependencies
260
+ npm install
261
+
262
+ # Build
263
+ npm run build
264
+
265
+ # Run tests
266
+ npx tsx test-sdk-full-coverage.ts
267
+
268
+ # Lint
269
+ npm run lint
270
+
271
+ # Format
272
+ npm run format
273
+ ```
274
+
275
+ ---
276
+
277
+ ## Current Status
278
+
279
+ ### v0.2.0 - Consolidated Program Architecture
280
+
281
+ **What's New:**
282
+ - Single consolidated program (Identity + Reputation + Validation)
283
+ - **Metaplex Core** NFTs (lighter, faster than Token Metadata)
284
+ - Global feedback index for simpler PDA derivation
285
+ - 89 comprehensive tests on devnet
286
+
287
+ **Breaking Changes from v0.1.0:**
288
+ - Program IDs changed (now single program)
289
+ - Agent PDA uses Core asset address, not mint
290
+ - Feedback PDA uses global index (no client address in seeds)
291
+ - Response PDA removed client from seeds
292
+
293
+ **Implemented:**
294
+ - Agent registration with Metaplex Core
295
+ - Metadata management + extensions
296
+ - Permissionless feedback system
297
+ - Reputation tracking with cached aggregates
298
+ - Validation requests and responses
299
+ - NFT-based agent identity
300
+ - Interface parity with agent0-ts
301
+
302
+ **Requires Custom RPC:**
303
+ - `getAgentsByOwner()` - Requires getProgramAccounts
304
+ - `readAllFeedback()` - Requires getProgramAccounts
305
+ - `getClients()` - Requires getProgramAccounts
306
+
307
+ ---
308
+
309
+ ## Operation Costs (Devnet Measured v0.2.0)
310
+
311
+ Costs measured via SDK E2E tests on Solana devnet:
312
+
313
+ | Operation | Total Cost | Lamports | Notes |
314
+ |-----------|------------|----------|-------|
315
+ | Register Agent | **0.00651 SOL** | 6,507,280 | Core asset + AgentAccount |
316
+ | Set On-chain Metadata (1st) | **0.00319 SOL** | 3,192,680 | +MetadataEntryPda |
317
+ | Set On-chain Metadata (update) | 0.000005 SOL | 5,000 | TX fee only |
318
+ | Give Feedback (1st) | 0.00332 SOL | 3,324,920 | Feedback + AgentReputation init |
319
+ | Give Feedback (2nd+) | 0.00209 SOL | 2,086,040 | FeedbackAccount only |
320
+ | Append Response (1st) | 0.00275 SOL | 2,747,240 | Response + ResponseIndex init |
321
+ | Append Response (2nd+) | 0.00163 SOL | 1,626,680 | ResponseAccount only |
322
+ | Revoke Feedback | 0.000005 SOL | 5,000 | TX fee only |
323
+ | Request Validation | 0.00183 SOL | 1,828,520 | ValidationRequest |
324
+ | Respond to Validation | 0.000005 SOL | 5,000 | TX fee only |
325
+ | **Full Lifecycle** | **0.0245 SOL** | 24,521,040 | Complete test cycle |
326
+
327
+ ### First vs Subsequent Cost Savings
328
+
329
+ | Operation | 1st Call | 2nd+ Calls | Savings |
330
+ |-----------|----------|------------|---------|
331
+ | Set On-chain Metadata | 0.00319 SOL | 0.000005 SOL | **-99%** |
332
+ | Give Feedback | 0.00332 SOL | 0.00209 SOL | **-37%** |
333
+ | Append Response | 0.00275 SOL | 0.00163 SOL | **-41%** |
334
+
335
+ First operation creates init_if_needed accounts. Subsequent calls skip initialization.
336
+
337
+ ### v0.2.0 Optimizations
338
+
339
+ | Optimization | Before | After | Savings |
340
+ |--------------|--------|-------|---------|
341
+ | FeedbackAccount | 375 bytes | 171 bytes | **-54%** |
342
+ | ResponseAccount | 309 bytes | 105 bytes | **-66%** |
343
+ | MetadataEntryPda | Vec (fixed) | Individual PDAs | Unlimited entries |
344
+
345
+ **v0.2.0 Changes:**
346
+ - **Hash-only storage**: URIs stored in events, only hashes on-chain
347
+ - **Individual Metadata PDAs**: Unlimited entries, deletable for rent recovery
348
+ - **Immutable on-chain metadata option**: Lock metadata permanently
349
+
350
+ ---
351
+
352
+ ## Contributing
353
+
354
+ Contributions welcome! This is a **public build** project.
355
+
356
+ ### How to Contribute
357
+
358
+ 1. **Fork** the repository
359
+ 2. **Create** a feature branch (`git checkout -b feature/amazing-feature`)
360
+ 3. **Commit** your changes (`git commit -m 'feat: add amazing feature'`)
361
+ 4. **Push** to the branch (`git push origin feature/amazing-feature`)
362
+ 5. **Open** a Pull Request
363
+
364
+ ### Contribution Guidelines
365
+
366
+ - Follow existing code style
367
+ - Add tests for new features
368
+ - Update documentation
369
+ - Use conventional commits
370
+
371
+ ---
372
+
373
+ ## Examples
374
+
375
+ See the `examples/` directory for complete usage examples:
376
+
377
+ | Example | Description |
378
+ |---------|-------------|
379
+ | [`quick-start.ts`](examples/quick-start.ts) | Basic read/write operations |
380
+ | [`feedback-usage.ts`](examples/feedback-usage.ts) | Submit and read feedback |
381
+ | [`agent-update.ts`](examples/agent-update.ts) | Update agent metadata |
382
+ | [`transfer-agent.ts`](examples/transfer-agent.ts) | Transfer agent ownership |
383
+ | [`server-mode.ts`](examples/server-mode.ts) | Server/client architecture with skipSend |
384
+
385
+ Run examples:
386
+ ```bash
387
+ # Set your private key (JSON array format)
388
+ export SOLANA_PRIVATE_KEY='[1,2,3,...]'
389
+
390
+ # Run example
391
+ npx tsx examples/quick-start.ts
392
+ ```
393
+
394
+ ---
395
+
396
+ ## License
397
+
398
+ MIT License - see [LICENSE](LICENSE) file for details.
399
+
400
+ ---
401
+
402
+ ## Links
403
+
404
+ - **ERC-8004 Standard**: [eips.ethereum.org/EIPS/eip-8004](https://eips.ethereum.org/EIPS/eip-8004)
405
+ - **agent0-ts Reference SDK**: [github.com/agent0lab/agent0-ts](https://github.com/agent0lab/agent0-ts)
406
+ - **Solana Programs**: [github.com/QuantuLabs/8004-solana](https://github.com/QuantuLabs/8004-solana)
407
+
408
+ ---
409
+
410
+ ## Acknowledgments
411
+
412
+ - Built with inspiration from the [agent0](https://github.com/agent0lab/agent0-ts) ecosystem
413
+ - Implements [ERC-8004](https://eips.ethereum.org/EIPS/eip-8004) standard on Solana
414
+ - Powered by Solana blockchain and Metaplex Core
415
+
416
+ ---
417
+
418
+ **Built for the Solana ecosystem** | v0.2.0
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Agent Mint Resolver
3
+ * Resolves agent_id (bigint) to agent_mint (PublicKey) using Identity Registry accounts
4
+ *
5
+ * Strategy:
6
+ * - Scan the Identity Registry program (not Metaplex!) for AgentAccount PDAs
7
+ * - Each AgentAccount contains agent_id and agent_mint
8
+ * - Load all agents once and cache for O(1) subsequent lookups
9
+ *
10
+ * This is MUCH faster than scanning Metaplex (millions of NFTs) because:
11
+ * - Identity Registry has only ~27 agents vs millions of Metaplex metadata accounts
12
+ * - Single getProgramAccounts call fetches all mappings
13
+ */
14
+ import { Connection, PublicKey } from '@solana/web3.js';
15
+ /**
16
+ * Agent Mint Resolver
17
+ * Maps agent_id → agent_mint using Identity Registry accounts
18
+ */
19
+ export declare class AgentMintResolver {
20
+ private cache;
21
+ private connection;
22
+ private cacheLoaded;
23
+ constructor(connection: Connection, _collectionMint?: PublicKey);
24
+ /**
25
+ * Resolve agent_id to agent_mint PublicKey
26
+ * @param agentId - Sequential agent ID (0, 1, 2...)
27
+ * @returns agent_mint PublicKey
28
+ * @throws Error if agent not found
29
+ */
30
+ resolve(agentId: bigint): Promise<PublicKey>;
31
+ /**
32
+ * Load all agents from Identity Registry and populate cache
33
+ * This is much faster than scanning Metaplex (one RPC call vs millions of accounts)
34
+ */
35
+ private loadAllAgents;
36
+ /**
37
+ * Manually add a mapping to cache (used after registration)
38
+ * @param agentId - Agent ID
39
+ * @param mint - Agent mint address
40
+ */
41
+ addToCache(agentId: bigint, mint: PublicKey): void;
42
+ /**
43
+ * Clear the cache (useful for testing or forcing refresh)
44
+ */
45
+ clearCache(): void;
46
+ /**
47
+ * Force reload all agents from chain
48
+ */
49
+ refresh(): Promise<void>;
50
+ /**
51
+ * Batch resolve multiple agent IDs
52
+ * More efficient than resolving one at a time
53
+ * @param agentIds - Array of agent IDs to resolve
54
+ * @returns Map of agent_id → agent_mint
55
+ */
56
+ batchResolve(agentIds: bigint[]): Promise<Map<bigint, PublicKey>>;
57
+ /**
58
+ * Get cache size (number of loaded agents)
59
+ */
60
+ get size(): number;
61
+ }
62
+ //# sourceMappingURL=agent-mint-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-mint-resolver.d.ts","sourceRoot":"","sources":["../../src/core/agent-mint-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAMxD;;;GAGG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,KAAK,CAAqC;IAClD,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,WAAW,CAAkB;gBAEzB,UAAU,EAAE,UAAU,EAAE,eAAe,CAAC,EAAE,SAAS;IAK/D;;;;;OAKG;IACG,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAwBlD;;;OAGG;YACW,aAAa;IAuC3B;;;;OAIG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI;IAIlD;;OAEG;IACH,UAAU,IAAI,IAAI;IAKlB;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAK9B;;;;;OAKG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAiBvE;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Agent Mint Resolver
3
+ * Resolves agent_id (bigint) to agent_mint (PublicKey) using Identity Registry accounts
4
+ *
5
+ * Strategy:
6
+ * - Scan the Identity Registry program (not Metaplex!) for AgentAccount PDAs
7
+ * - Each AgentAccount contains agent_id and agent_mint
8
+ * - Load all agents once and cache for O(1) subsequent lookups
9
+ *
10
+ * This is MUCH faster than scanning Metaplex (millions of NFTs) because:
11
+ * - Identity Registry has only ~27 agents vs millions of Metaplex metadata accounts
12
+ * - Single getProgramAccounts call fetches all mappings
13
+ */
14
+ import { AgentAccount } from './borsh-schemas.js';
15
+ import { ACCOUNT_DISCRIMINATORS } from './instruction-discriminators.js';
16
+ import { IDENTITY_PROGRAM_ID } from './pda-helpers.js';
17
+ import bs58 from 'bs58';
18
+ /**
19
+ * Agent Mint Resolver
20
+ * Maps agent_id → agent_mint using Identity Registry accounts
21
+ */
22
+ export class AgentMintResolver {
23
+ constructor(connection, _collectionMint) {
24
+ this.cache = new Map();
25
+ this.cacheLoaded = false;
26
+ this.connection = connection;
27
+ // collectionMint is no longer needed (was for Metaplex filtering)
28
+ }
29
+ /**
30
+ * Resolve agent_id to agent_mint PublicKey
31
+ * @param agentId - Sequential agent ID (0, 1, 2...)
32
+ * @returns agent_mint PublicKey
33
+ * @throws Error if agent not found
34
+ */
35
+ async resolve(agentId) {
36
+ const cacheKey = agentId.toString();
37
+ // Check cache first (O(1))
38
+ if (this.cache.has(cacheKey)) {
39
+ return this.cache.get(cacheKey);
40
+ }
41
+ // If cache not loaded, load all agents from Identity Registry
42
+ if (!this.cacheLoaded) {
43
+ await this.loadAllAgents();
44
+ }
45
+ // Now check cache again
46
+ const mint = this.cache.get(cacheKey);
47
+ if (!mint) {
48
+ throw new Error(`Agent #${agentId} not found. The agent may not exist.`);
49
+ }
50
+ return mint;
51
+ }
52
+ /**
53
+ * Load all agents from Identity Registry and populate cache
54
+ * This is much faster than scanning Metaplex (one RPC call vs millions of accounts)
55
+ */
56
+ async loadAllAgents() {
57
+ try {
58
+ // Get AgentAccount discriminator bytes for filtering
59
+ const discriminatorBytes = bs58.encode(ACCOUNT_DISCRIMINATORS.AgentAccount);
60
+ // Fetch ALL AgentAccount PDAs from Identity Registry (single RPC call)
61
+ const accounts = await this.connection.getProgramAccounts(IDENTITY_PROGRAM_ID, {
62
+ filters: [
63
+ {
64
+ memcmp: {
65
+ offset: 0,
66
+ bytes: discriminatorBytes,
67
+ },
68
+ },
69
+ ],
70
+ });
71
+ // Parse each account and populate cache
72
+ for (const { account } of accounts) {
73
+ try {
74
+ const agentAccount = AgentAccount.deserialize(Buffer.from(account.data));
75
+ const agentId = agentAccount.agent_id.toString();
76
+ const agentMint = agentAccount.getMintPublicKey();
77
+ this.cache.set(agentId, agentMint);
78
+ }
79
+ catch {
80
+ // Skip malformed accounts
81
+ continue;
82
+ }
83
+ }
84
+ this.cacheLoaded = true;
85
+ console.log(`AgentMintResolver: Loaded ${this.cache.size} agents from Identity Registry`);
86
+ }
87
+ catch (error) {
88
+ console.error(`Error loading agents from Identity Registry: ${error}`);
89
+ throw new Error(`Failed to load agents: ${error}`);
90
+ }
91
+ }
92
+ /**
93
+ * Manually add a mapping to cache (used after registration)
94
+ * @param agentId - Agent ID
95
+ * @param mint - Agent mint address
96
+ */
97
+ addToCache(agentId, mint) {
98
+ this.cache.set(agentId.toString(), mint);
99
+ }
100
+ /**
101
+ * Clear the cache (useful for testing or forcing refresh)
102
+ */
103
+ clearCache() {
104
+ this.cache.clear();
105
+ this.cacheLoaded = false;
106
+ }
107
+ /**
108
+ * Force reload all agents from chain
109
+ */
110
+ async refresh() {
111
+ this.clearCache();
112
+ await this.loadAllAgents();
113
+ }
114
+ /**
115
+ * Batch resolve multiple agent IDs
116
+ * More efficient than resolving one at a time
117
+ * @param agentIds - Array of agent IDs to resolve
118
+ * @returns Map of agent_id → agent_mint
119
+ */
120
+ async batchResolve(agentIds) {
121
+ // Ensure cache is loaded
122
+ if (!this.cacheLoaded) {
123
+ await this.loadAllAgents();
124
+ }
125
+ const results = new Map();
126
+ for (const agentId of agentIds) {
127
+ const mint = this.cache.get(agentId.toString());
128
+ if (mint) {
129
+ results.set(agentId, mint);
130
+ }
131
+ }
132
+ return results;
133
+ }
134
+ /**
135
+ * Get cache size (number of loaded agents)
136
+ */
137
+ get size() {
138
+ return this.cache.size;
139
+ }
140
+ }
141
+ //# sourceMappingURL=agent-mint-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-mint-resolver.js","sourceRoot":"","sources":["../../src/core/agent-mint-resolver.ts"],"names":[],"mappings":"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"}