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.
- package/LICENSE +21 -0
- package/README.md +418 -0
- package/dist/core/agent-mint-resolver.d.ts +62 -0
- package/dist/core/agent-mint-resolver.d.ts.map +1 -0
- package/dist/core/agent-mint-resolver.js +141 -0
- package/dist/core/agent-mint-resolver.js.map +1 -0
- package/dist/core/borsh-schemas.d.ts +306 -0
- package/dist/core/borsh-schemas.d.ts.map +1 -0
- package/dist/core/borsh-schemas.js +552 -0
- package/dist/core/borsh-schemas.js.map +1 -0
- package/dist/core/client.d.ts +103 -0
- package/dist/core/client.d.ts.map +1 -0
- package/dist/core/client.js +177 -0
- package/dist/core/client.js.map +1 -0
- package/dist/core/config-reader.d.ts +19 -0
- package/dist/core/config-reader.d.ts.map +1 -0
- package/dist/core/config-reader.js +35 -0
- package/dist/core/config-reader.js.map +1 -0
- package/dist/core/endpoint-crawler.d.ts +44 -0
- package/dist/core/endpoint-crawler.d.ts.map +1 -0
- package/dist/core/endpoint-crawler.js +280 -0
- package/dist/core/endpoint-crawler.js.map +1 -0
- package/dist/core/feedback-auth.d.ts +184 -0
- package/dist/core/feedback-auth.d.ts.map +1 -0
- package/dist/core/feedback-auth.js +232 -0
- package/dist/core/feedback-auth.js.map +1 -0
- package/dist/core/feedback-manager-solana.d.ts +117 -0
- package/dist/core/feedback-manager-solana.d.ts.map +1 -0
- package/dist/core/feedback-manager-solana.js +279 -0
- package/dist/core/feedback-manager-solana.js.map +1 -0
- package/dist/core/instruction-builder.d.ts +122 -0
- package/dist/core/instruction-builder.d.ts.map +1 -0
- package/dist/core/instruction-builder.js +451 -0
- package/dist/core/instruction-builder.js.map +1 -0
- package/dist/core/instruction-discriminators.d.ts +84 -0
- package/dist/core/instruction-discriminators.d.ts.map +1 -0
- package/dist/core/instruction-discriminators.js +102 -0
- package/dist/core/instruction-discriminators.js.map +1 -0
- package/dist/core/ipfs-client.d.ts +88 -0
- package/dist/core/ipfs-client.d.ts.map +1 -0
- package/dist/core/ipfs-client.js +321 -0
- package/dist/core/ipfs-client.js.map +1 -0
- package/dist/core/metaplex-helpers.d.ts +26 -0
- package/dist/core/metaplex-helpers.d.ts.map +1 -0
- package/dist/core/metaplex-helpers.js +44 -0
- package/dist/core/metaplex-helpers.js.map +1 -0
- package/dist/core/oasf-validator.d.ts +16 -0
- package/dist/core/oasf-validator.d.ts.map +1 -0
- package/dist/core/oasf-validator.js +26 -0
- package/dist/core/oasf-validator.js.map +1 -0
- package/dist/core/pda-helpers.d.ts +102 -0
- package/dist/core/pda-helpers.d.ts.map +1 -0
- package/dist/core/pda-helpers.js +175 -0
- package/dist/core/pda-helpers.js.map +1 -0
- package/dist/core/programs.d.ts +100 -0
- package/dist/core/programs.d.ts.map +1 -0
- package/dist/core/programs.js +108 -0
- package/dist/core/programs.js.map +1 -0
- package/dist/core/sdk-solana.d.ts +311 -0
- package/dist/core/sdk-solana.d.ts.map +1 -0
- package/dist/core/sdk-solana.js +597 -0
- package/dist/core/sdk-solana.js.map +1 -0
- package/dist/core/transaction-builder.d.ts +220 -0
- package/dist/core/transaction-builder.d.ts.map +1 -0
- package/dist/core/transaction-builder.js +822 -0
- package/dist/core/transaction-builder.js.map +1 -0
- package/dist/core/utils.d.ts +17 -0
- package/dist/core/utils.d.ts.map +1 -0
- package/dist/core/utils.js +24 -0
- package/dist/core/utils.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/models/enums.d.ts +23 -0
- package/dist/models/enums.d.ts.map +1 -0
- package/dist/models/enums.js +25 -0
- package/dist/models/enums.js.map +1 -0
- package/dist/models/index.d.ts +8 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/models/index.js +8 -0
- package/dist/models/index.js.map +1 -0
- package/dist/models/interfaces.d.ts +160 -0
- package/dist/models/interfaces.d.ts.map +1 -0
- package/dist/models/interfaces.js +5 -0
- package/dist/models/interfaces.js.map +1 -0
- package/dist/models/types.d.ts +11 -0
- package/dist/models/types.d.ts.map +1 -0
- package/dist/models/types.js +5 -0
- package/dist/models/types.js.map +1 -0
- package/dist/taxonomies/all_domains.json +1565 -0
- package/dist/taxonomies/all_skills.json +1030 -0
- package/dist/utils/constants.d.ts +43 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +51 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/id-format.d.ts +30 -0
- package/dist/utils/id-format.d.ts.map +1 -0
- package/dist/utils/id-format.js +67 -0
- package/dist/utils/id-format.js.map +1 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +8 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/registration-file-builder.d.ts +15 -0
- package/dist/utils/registration-file-builder.d.ts.map +1 -0
- package/dist/utils/registration-file-builder.js +54 -0
- package/dist/utils/registration-file-builder.js.map +1 -0
- package/dist/utils/validation.d.ts +25 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +61 -0
- package/dist/utils/validation.js.map +1 -0
- 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
|
+
[](https://www.npmjs.com/package/8004-solana)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
[](https://github.com/QuantuLabs/8004-solana-ts)
|
|
9
|
+
[](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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"}
|