@agether/sdk 2.12.2 → 2.14.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.
@@ -0,0 +1,200 @@
1
+ /**
2
+ * AgentIdentityClient - Integration with ag0 (ERC-8004)
3
+ *
4
+ * ERC-8004 is a per-chain singleton — different chain = different agentId.
5
+ *
6
+ * Contract Addresses:
7
+ * - Ethereum IdentityRegistry: 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432
8
+ * - Base IdentityRegistry: 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432
9
+ * - Sepolia IdentityRegistry: 0x8004A818BFB912233c491871b3d84c89A494BD9e
10
+ * - Sepolia ReputationRegistry: 0x8004B663056A597Dffe9eCcC1965A193B7388713
11
+ *
12
+ * SDKs:
13
+ * - TypeScript: https://github.com/agent0lab/agent0-ts
14
+ * - Python: https://github.com/agent0lab/agent0-py
15
+ *
16
+ * Docs: https://sdk.ag0.xyz/docs
17
+ */
18
+ import { Signer } from 'ethers';
19
+ import { AgetherConfig } from '../types';
20
+ export declare const ERC8004_SEPOLIA: {
21
+ identityRegistry: string;
22
+ reputationRegistry: string;
23
+ };
24
+ export declare const ERC8004_MAINNET: {
25
+ identityRegistry: string;
26
+ reputationRegistry: string;
27
+ };
28
+ export declare const ERC8004_BASE: {
29
+ identityRegistry: string;
30
+ reputationRegistry: string;
31
+ };
32
+ export interface AgentIdentityClientOptions {
33
+ config: AgetherConfig;
34
+ signer: Signer;
35
+ /** Optional: Use ag0 TypeScript SDK instead of direct contracts */
36
+ useAg0SDK?: boolean;
37
+ }
38
+ export interface AgentMetadata {
39
+ name: string;
40
+ description: string;
41
+ image?: string;
42
+ endpoints?: {
43
+ name: string;
44
+ endpoint: string;
45
+ version?: string;
46
+ }[];
47
+ x402Support?: boolean;
48
+ active?: boolean;
49
+ }
50
+ export interface FeedbackInput {
51
+ agentId: bigint;
52
+ value: number;
53
+ decimals?: number;
54
+ tag1?: string;
55
+ tag2?: string;
56
+ endpoint?: string;
57
+ feedbackURI?: string;
58
+ }
59
+ export interface ReputationSummary {
60
+ count: number;
61
+ totalValue: number;
62
+ averageValue: number;
63
+ clients: string[];
64
+ }
65
+ export declare class AgentIdentityClient {
66
+ readonly config: AgetherConfig;
67
+ private signer;
68
+ private identityRegistry;
69
+ private reputationRegistry;
70
+ constructor(options: AgentIdentityClientOptions);
71
+ /**
72
+ * Register a new agent (minimal - no metadata)
73
+ */
74
+ register(): Promise<{
75
+ agentId: bigint;
76
+ txHash: string;
77
+ }>;
78
+ /**
79
+ * Register agent with IPFS/HTTP URI to metadata JSON
80
+ * @param agentURI URI pointing to agent metadata (ipfs:// or https://)
81
+ */
82
+ registerWithURI(agentURI: string): Promise<{
83
+ agentId: bigint;
84
+ txHash: string;
85
+ }>;
86
+ /**
87
+ * Check if the signer already owns an ERC-8004 identity token.
88
+ * Returns true if balanceOf > 0, false otherwise.
89
+ * Note: Cannot determine the specific agentId without enumeration —
90
+ * use agether init <pk> --agent-id <id> if you know your agentId.
91
+ */
92
+ hasExistingIdentity(): Promise<boolean>;
93
+ /**
94
+ * Register only if no identity exists; otherwise throw.
95
+ * Prevents accidental double-registration.
96
+ */
97
+ registerOrGet(): Promise<{
98
+ agentId: bigint;
99
+ txHash: string | null;
100
+ existing: boolean;
101
+ }>;
102
+ /**
103
+ * Register with URI only if no identity exists; otherwise throw.
104
+ * Prevents accidental double-registration.
105
+ */
106
+ registerOrGetWithURI(agentURI: string): Promise<{
107
+ agentId: bigint;
108
+ txHash: string | null;
109
+ existing: boolean;
110
+ }>;
111
+ /**
112
+ * Register agent with URI and onchain metadata
113
+ */
114
+ registerWithMetadata(agentURI: string, metadata: {
115
+ key: string;
116
+ value: string;
117
+ }[]): Promise<{
118
+ agentId: bigint;
119
+ txHash: string;
120
+ }>;
121
+ /**
122
+ * Get agent owner address
123
+ */
124
+ getOwner(agentId: bigint): Promise<string>;
125
+ /**
126
+ * Get agent URI (metadata JSON location)
127
+ */
128
+ getAgentURI(agentId: bigint): Promise<string>;
129
+ /**
130
+ * Update agent URI
131
+ */
132
+ setAgentURI(agentId: bigint, newURI: string): Promise<string>;
133
+ /**
134
+ * Set onchain metadata (key-value)
135
+ */
136
+ setMetadata(agentId: bigint, key: string, value: string): Promise<string>;
137
+ /**
138
+ * Get onchain metadata
139
+ */
140
+ getMetadata(agentId: bigint, key: string): Promise<string>;
141
+ /**
142
+ * Transfer agent to new owner
143
+ */
144
+ transfer(agentId: bigint, to: string): Promise<string>;
145
+ /**
146
+ * Fetch and parse agent metadata from URI
147
+ */
148
+ fetchAgentMetadata(agentId: bigint): Promise<AgentMetadata | null>;
149
+ /**
150
+ * Give feedback to an agent
151
+ */
152
+ giveFeedback(input: FeedbackInput): Promise<string>;
153
+ /**
154
+ * Give positive feedback (shorthand)
155
+ */
156
+ givePosisitiveFeedback(agentId: bigint, value?: number, tags?: {
157
+ tag1?: string;
158
+ tag2?: string;
159
+ }): Promise<string>;
160
+ /**
161
+ * Give negative feedback (e.g., for defaults)
162
+ */
163
+ giveNegativeFeedback(agentId: bigint, value?: number, tags?: {
164
+ tag1?: string;
165
+ tag2?: string;
166
+ }): Promise<string>;
167
+ /**
168
+ * Record credit default in reputation system
169
+ */
170
+ recordCreditDefault(agentId: bigint, creditLineId: bigint): Promise<string>;
171
+ /**
172
+ * Get reputation summary for an agent
173
+ */
174
+ getReputation(agentId: bigint, tag1?: string, tag2?: string): Promise<ReputationSummary>;
175
+ /**
176
+ * Check if agent has negative credit reputation
177
+ */
178
+ hasNegativeCreditReputation(agentId: bigint): Promise<boolean>;
179
+ /**
180
+ * Verify agent is eligible for Agether credit
181
+ * Checks:
182
+ * 1. Agent exists in ERC-8004 registry
183
+ * 2. Agent has no negative credit reputation
184
+ */
185
+ verifyForCredit(agentId: bigint): Promise<{
186
+ eligible: boolean;
187
+ reason?: string;
188
+ owner?: string;
189
+ reputation?: ReputationSummary;
190
+ }>;
191
+ private parseAgentIdFromReceipt;
192
+ /**
193
+ * Get contract addresses
194
+ */
195
+ getContractAddresses(): {
196
+ identity: string;
197
+ reputation: string;
198
+ };
199
+ }
200
+ //# sourceMappingURL=AgentIdentityClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AgentIdentityClient.d.ts","sourceRoot":"","sources":["../../src/clients/AgentIdentityClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,351 @@
1
+ /**
2
+ * AgentIdentityClient - Integration with ag0 (ERC-8004)
3
+ *
4
+ * ERC-8004 is a per-chain singleton — different chain = different agentId.
5
+ *
6
+ * Contract Addresses:
7
+ * - Ethereum IdentityRegistry: 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432
8
+ * - Base IdentityRegistry: 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432
9
+ * - Sepolia IdentityRegistry: 0x8004A818BFB912233c491871b3d84c89A494BD9e
10
+ * - Sepolia ReputationRegistry: 0x8004B663056A597Dffe9eCcC1965A193B7388713
11
+ *
12
+ * SDKs:
13
+ * - TypeScript: https://github.com/agent0lab/agent0-ts
14
+ * - Python: https://github.com/agent0lab/agent0-py
15
+ *
16
+ * Docs: https://sdk.ag0.xyz/docs
17
+ */
18
+ import { ethers } from 'ethers';
19
+ // ERC-8004 ABI fragments
20
+ const ERC8004_IDENTITY_ABI = [
21
+ // Registration
22
+ 'function register() returns (uint256)',
23
+ 'function register(string agentURI) returns (uint256)',
24
+ 'function register(string agentURI, tuple(string key, bytes value)[] metadata) returns (uint256)',
25
+ // Management
26
+ 'function setAgentURI(uint256 agentId, string newURI)',
27
+ 'function setMetadata(uint256 agentId, string metadataKey, bytes metadataValue)',
28
+ 'function getMetadata(uint256 agentId, string metadataKey) view returns (bytes)',
29
+ // ERC-721 standard
30
+ 'function ownerOf(uint256 tokenId) view returns (address)',
31
+ 'function balanceOf(address owner) view returns (uint256)',
32
+ 'function tokenURI(uint256 tokenId) view returns (string)',
33
+ 'function transferFrom(address from, address to, uint256 tokenId)',
34
+ 'function approve(address to, uint256 tokenId)',
35
+ 'function getApproved(uint256 tokenId) view returns (address)',
36
+ // Events
37
+ 'event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)',
38
+ ];
39
+ const ERC8004_REPUTATION_ABI = [
40
+ // Feedback
41
+ 'function giveFeedback(uint256 agentId, int128 value, uint8 valueDecimals, string tag1, string tag2, string endpoint, string feedbackURI, bytes32 feedbackHash)',
42
+ 'function revokeFeedback(uint256 agentId, uint64 feedbackIndex)',
43
+ // Queries
44
+ 'function readFeedback(uint256 agentId, address clientAddress, uint64 feedbackIndex) view returns (int128 value, uint8 valueDecimals, string tag1, string tag2, bool isRevoked)',
45
+ 'function getSummary(uint256 agentId, address[] clientAddresses, string tag1, string tag2) view returns (uint64 count, int128 summaryValue, uint8 summaryValueDecimals)',
46
+ 'function getClients(uint256 agentId) view returns (address[])',
47
+ 'function getLastIndex(uint256 agentId, address clientAddress) view returns (uint64)',
48
+ // Registry
49
+ 'function getIdentityRegistry() view returns (address)',
50
+ ];
51
+ // ERC-8004 Sepolia addresses
52
+ export const ERC8004_SEPOLIA = {
53
+ identityRegistry: '0x8004A818BFB912233c491871b3d84c89A494BD9e',
54
+ reputationRegistry: '0x8004B663056A597Dffe9eCcC1965A193B7388713',
55
+ };
56
+ // ERC-8004 Ethereum mainnet singleton
57
+ export const ERC8004_MAINNET = {
58
+ identityRegistry: '0x8004A169FB4a3325136EB29fA0ceB6D2e539a432',
59
+ reputationRegistry: '', // Not yet deployed on mainnet
60
+ };
61
+ // ERC-8004 Base mainnet singleton
62
+ export const ERC8004_BASE = {
63
+ identityRegistry: '0x8004A169FB4a3325136EB29fA0ceB6D2e539a432',
64
+ reputationRegistry: '', // Not yet deployed on Base
65
+ };
66
+ export class AgentIdentityClient {
67
+ constructor(options) {
68
+ this.config = options.config;
69
+ this.signer = options.signer;
70
+ // Get registry addresses (prefer config, fallback to Sepolia)
71
+ const identityAddr = options.config.contracts?.identityRegistry || ERC8004_SEPOLIA.identityRegistry;
72
+ const reputationAddr = options.config.contracts?.reputationRegistry || ERC8004_SEPOLIA.reputationRegistry;
73
+ this.identityRegistry = new ethers.Contract(identityAddr, ERC8004_IDENTITY_ABI, this.signer);
74
+ this.reputationRegistry = new ethers.Contract(reputationAddr, ERC8004_REPUTATION_ABI, this.signer);
75
+ }
76
+ // ============ Identity Functions ============
77
+ /**
78
+ * Register a new agent (minimal - no metadata)
79
+ */
80
+ async register() {
81
+ const tx = await this.identityRegistry['register()']();
82
+ const receipt = await tx.wait();
83
+ const agentId = this.parseAgentIdFromReceipt(receipt);
84
+ return { agentId, txHash: receipt.hash };
85
+ }
86
+ /**
87
+ * Register agent with IPFS/HTTP URI to metadata JSON
88
+ * @param agentURI URI pointing to agent metadata (ipfs:// or https://)
89
+ */
90
+ async registerWithURI(agentURI) {
91
+ const tx = await this.identityRegistry['register(string)'](agentURI);
92
+ const receipt = await tx.wait();
93
+ const agentId = this.parseAgentIdFromReceipt(receipt);
94
+ return { agentId, txHash: receipt.hash };
95
+ }
96
+ /**
97
+ * Check if the signer already owns an ERC-8004 identity token.
98
+ * Returns true if balanceOf > 0, false otherwise.
99
+ * Note: Cannot determine the specific agentId without enumeration —
100
+ * use agether init <pk> --agent-id <id> if you know your agentId.
101
+ */
102
+ async hasExistingIdentity() {
103
+ try {
104
+ const address = await this.signer.getAddress();
105
+ const balance = await this.identityRegistry.balanceOf(address);
106
+ return balance > 0n;
107
+ }
108
+ catch (e) {
109
+ console.warn('[agether] hasExistingIdentity check failed:', e instanceof Error ? e.message : e);
110
+ return false;
111
+ }
112
+ }
113
+ /**
114
+ * Register only if no identity exists; otherwise throw.
115
+ * Prevents accidental double-registration.
116
+ */
117
+ async registerOrGet() {
118
+ const hasIdentity = await this.hasExistingIdentity();
119
+ if (hasIdentity) {
120
+ throw new Error('Wallet already owns an ERC-8004 identity. Use agether init <pk> --agent-id <id> to set it.');
121
+ }
122
+ const result = await this.register();
123
+ return { ...result, existing: false };
124
+ }
125
+ /**
126
+ * Register with URI only if no identity exists; otherwise throw.
127
+ * Prevents accidental double-registration.
128
+ */
129
+ async registerOrGetWithURI(agentURI) {
130
+ const hasIdentity = await this.hasExistingIdentity();
131
+ if (hasIdentity) {
132
+ throw new Error('Wallet already owns an ERC-8004 identity. Use agether init <pk> --agent-id <id> to set it.');
133
+ }
134
+ const result = await this.registerWithURI(agentURI);
135
+ return { ...result, existing: false };
136
+ }
137
+ /**
138
+ * Register agent with URI and onchain metadata
139
+ */
140
+ async registerWithMetadata(agentURI, metadata) {
141
+ const metadataEntries = metadata.map(m => ({
142
+ key: m.key,
143
+ value: ethers.toUtf8Bytes(m.value),
144
+ }));
145
+ const tx = await this.identityRegistry['register(string,tuple(string,bytes)[])'](agentURI, metadataEntries);
146
+ const receipt = await tx.wait();
147
+ const agentId = this.parseAgentIdFromReceipt(receipt);
148
+ return { agentId, txHash: receipt.hash };
149
+ }
150
+ /**
151
+ * Get agent owner address
152
+ */
153
+ async getOwner(agentId) {
154
+ return await this.identityRegistry.ownerOf(agentId);
155
+ }
156
+ /**
157
+ * Get agent URI (metadata JSON location)
158
+ */
159
+ async getAgentURI(agentId) {
160
+ return await this.identityRegistry.tokenURI(agentId);
161
+ }
162
+ /**
163
+ * Update agent URI
164
+ */
165
+ async setAgentURI(agentId, newURI) {
166
+ const tx = await this.identityRegistry.setAgentURI(agentId, newURI);
167
+ const receipt = await tx.wait();
168
+ return receipt.hash;
169
+ }
170
+ /**
171
+ * Set onchain metadata (key-value)
172
+ */
173
+ async setMetadata(agentId, key, value) {
174
+ const tx = await this.identityRegistry.setMetadata(agentId, key, ethers.toUtf8Bytes(value));
175
+ const receipt = await tx.wait();
176
+ return receipt.hash;
177
+ }
178
+ /**
179
+ * Get onchain metadata
180
+ */
181
+ async getMetadata(agentId, key) {
182
+ const value = await this.identityRegistry.getMetadata(agentId, key);
183
+ return ethers.toUtf8String(value);
184
+ }
185
+ /**
186
+ * Transfer agent to new owner
187
+ */
188
+ async transfer(agentId, to) {
189
+ const from = await this.signer.getAddress();
190
+ const tx = await this.identityRegistry.transferFrom(from, to, agentId);
191
+ const receipt = await tx.wait();
192
+ return receipt.hash;
193
+ }
194
+ /**
195
+ * Fetch and parse agent metadata from URI
196
+ */
197
+ async fetchAgentMetadata(agentId) {
198
+ try {
199
+ const uri = await this.getAgentURI(agentId);
200
+ // Handle IPFS URIs
201
+ let fetchUrl = uri;
202
+ if (uri.startsWith('ipfs://')) {
203
+ const cid = uri.replace('ipfs://', '');
204
+ fetchUrl = `https://ipfs.io/ipfs/${cid}`;
205
+ }
206
+ const response = await fetch(fetchUrl);
207
+ if (!response.ok)
208
+ return null;
209
+ return await response.json();
210
+ }
211
+ catch (e) {
212
+ console.warn('[agether] getMetadata fetch failed:', e instanceof Error ? e.message : e);
213
+ return null;
214
+ }
215
+ }
216
+ // ============ Reputation Functions ============
217
+ /**
218
+ * Give feedback to an agent
219
+ */
220
+ async giveFeedback(input) {
221
+ const feedbackHash = ethers.keccak256(ethers.AbiCoder.defaultAbiCoder().encode(['uint256', 'int128', 'uint256'], [input.agentId, input.value, Date.now()]));
222
+ const tx = await this.reputationRegistry.giveFeedback(input.agentId, input.value, input.decimals || 0, input.tag1 || '', input.tag2 || '', input.endpoint || '', input.feedbackURI || '', feedbackHash);
223
+ const receipt = await tx.wait();
224
+ return receipt.hash;
225
+ }
226
+ /**
227
+ * Give positive feedback (shorthand)
228
+ */
229
+ async givePosisitiveFeedback(agentId, value = 100, tags = {}) {
230
+ return this.giveFeedback({
231
+ agentId,
232
+ value: Math.abs(value),
233
+ ...tags,
234
+ });
235
+ }
236
+ /**
237
+ * Give negative feedback (e.g., for defaults)
238
+ */
239
+ async giveNegativeFeedback(agentId, value = -100, tags = {}) {
240
+ return this.giveFeedback({
241
+ agentId,
242
+ value: -Math.abs(value),
243
+ ...tags,
244
+ });
245
+ }
246
+ /**
247
+ * Record credit default in reputation system
248
+ */
249
+ async recordCreditDefault(agentId, creditLineId) {
250
+ return this.giveFeedback({
251
+ agentId,
252
+ value: -100,
253
+ tag1: 'credit',
254
+ tag2: 'default',
255
+ feedbackURI: `agether://default/${creditLineId}`,
256
+ });
257
+ }
258
+ /**
259
+ * Get reputation summary for an agent
260
+ */
261
+ async getReputation(agentId, tag1 = '', tag2 = '') {
262
+ const clients = await this.reputationRegistry.getClients(agentId);
263
+ if (clients.length === 0) {
264
+ return {
265
+ count: 0,
266
+ totalValue: 0,
267
+ averageValue: 0,
268
+ clients: [],
269
+ };
270
+ }
271
+ const [count, summaryValue, decimals] = await this.reputationRegistry.getSummary(agentId, clients, tag1, tag2);
272
+ // Convert from fixed-point
273
+ const divisor = 10 ** Number(decimals);
274
+ const total = Number(summaryValue) / divisor;
275
+ return {
276
+ count: Number(count),
277
+ totalValue: total,
278
+ averageValue: Number(count) > 0 ? total / Number(count) : 0,
279
+ clients: clients.map((c) => c),
280
+ };
281
+ }
282
+ /**
283
+ * Check if agent has negative credit reputation
284
+ */
285
+ async hasNegativeCreditReputation(agentId) {
286
+ const rep = await this.getReputation(agentId, 'credit', '');
287
+ return rep.count > 0 && rep.averageValue < 0;
288
+ }
289
+ // ============ Agether Integration ============
290
+ /**
291
+ * Verify agent is eligible for Agether credit
292
+ * Checks:
293
+ * 1. Agent exists in ERC-8004 registry
294
+ * 2. Agent has no negative credit reputation
295
+ */
296
+ async verifyForCredit(agentId) {
297
+ // Check agent exists
298
+ let owner;
299
+ try {
300
+ owner = await this.getOwner(agentId);
301
+ }
302
+ catch (e) {
303
+ console.warn('[agether] checkCreditEligibility: agent not found:', e instanceof Error ? e.message : e);
304
+ return { eligible: false, reason: 'Agent not found in ERC-8004 registry' };
305
+ }
306
+ // Check credit reputation
307
+ const reputation = await this.getReputation(agentId, 'credit', '');
308
+ if (reputation.count > 0 && reputation.averageValue < 0) {
309
+ return {
310
+ eligible: false,
311
+ reason: 'Agent has negative credit reputation',
312
+ owner,
313
+ reputation,
314
+ };
315
+ }
316
+ return {
317
+ eligible: true,
318
+ owner,
319
+ reputation,
320
+ };
321
+ }
322
+ // ============ Helpers ============
323
+ parseAgentIdFromReceipt(receipt) {
324
+ // Find Transfer event (ERC-721)
325
+ for (const log of receipt.logs) {
326
+ try {
327
+ const parsed = this.identityRegistry.interface.parseLog({
328
+ topics: log.topics,
329
+ data: log.data,
330
+ });
331
+ if (parsed?.name === 'Transfer') {
332
+ return parsed.args[2]; // tokenId
333
+ }
334
+ }
335
+ catch (e) {
336
+ console.warn('[agether] parseAgentIdFromReceipt parseLog skip:', e instanceof Error ? e.message : e);
337
+ continue;
338
+ }
339
+ }
340
+ return 0n;
341
+ }
342
+ /**
343
+ * Get contract addresses
344
+ */
345
+ getContractAddresses() {
346
+ return {
347
+ identity: this.identityRegistry.target,
348
+ reputation: this.reputationRegistry.target,
349
+ };
350
+ }
351
+ }