@brainai/satp-client 2.0.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/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # SATP JavaScript SDK
2
+
3
+ Lightweight SDK for interacting with SATP (Solana Agent Token Protocol) programs on Solana.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ cd satp-sdk && npm install
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```js
14
+ const { SATPSDK } = require('./src');
15
+
16
+ const sdk = new SATPSDK(); // mainnet by default
17
+ // const sdk = new SATPSDK({ rpcUrl: 'https://api.devnet.solana.com' });
18
+
19
+ // Check if an agent is registered
20
+ const verified = await sdk.verifyAgent('SomeWalletPubkey...');
21
+
22
+ // Get identity data
23
+ const identity = await sdk.getIdentity('SomeWalletPubkey...');
24
+
25
+ // Get reputation
26
+ const rep = await sdk.getReputation('SomeWalletPubkey...');
27
+
28
+ // Derive PDAs (offline, no RPC)
29
+ const pdas = sdk.getPDAs('SomeWalletPubkey...');
30
+ ```
31
+
32
+ ## Write Operations (require a signer)
33
+
34
+ ```js
35
+ const { Keypair } = require('@solana/web3.js');
36
+
37
+ const signer = Keypair.fromSecretKey(/* your key */);
38
+
39
+ // Register identity
40
+ const sig = await sdk.registerIdentity(signer, 'my-agent', { type: 'ai', version: '1.0' });
41
+
42
+ // Add reputation (endorser signs)
43
+ const sig2 = await sdk.addReputation(endorserKeypair, targetWallet, 100);
44
+ ```
45
+
46
+ ## Transaction Builders (for wallet adapters / frontends)
47
+
48
+ ```js
49
+ // Get unsigned transaction for frontend signing
50
+ const { transaction, identityPDA } = await sdk.buildRegisterIdentity(
51
+ walletPublicKey, 'agent-name', { metadata: true }
52
+ );
53
+ // Sign with wallet adapter, then send
54
+ ```
55
+
56
+ ## API
57
+
58
+ | Method | Type | Description |
59
+ |--------|------|-------------|
60
+ | `getIdentity(wallet)` | Read | Fetch identity data (or null) |
61
+ | `getReputation(wallet)` | Read | Fetch reputation data (or null) |
62
+ | `verifyAgent(wallet)` | Read | Check if wallet has SATP identity |
63
+ | `getPDAs(wallet)` | Offline | Derive identity + reputation PDAs |
64
+ | `registerIdentity(signer, name, metadata)` | Write | Register on-chain identity |
65
+ | `addReputation(endorser, target, score)` | Write | Add reputation score |
66
+ | `buildRegisterIdentity(wallet, name, meta)` | Builder | Unsigned tx for frontends |
67
+ | `buildAddReputation(wallet, score, endorser)` | Builder | Unsigned tx for frontends |
68
+
69
+ ## Program IDs (Mainnet)
70
+
71
+ | Program | Address |
72
+ |---------|---------|
73
+ | Identity | `BY4jzmnrui1K5gZ5z5xRQkVfEEMXYHYugtH1Ua867eyr` |
74
+ | Reputation | `TQ4P9R2Y5FRyw1TZfwoWQ2Mf6XeohbGdhYNcDxh6YYh` |
75
+ | Validation | `AdDWFa9oEmZdrTrhu8YTWu4ozbTP7e6qa9rvyqfAvM7N` |
76
+ | Escrow | `STyY8w4ZHws3X1AMoocWuDYBoogVDwvymPy8Wifx5TH` |
77
+
78
+ ## Notes
79
+
80
+ - Account schemas are best-guess based on Anchor conventions. Once we have the actual IDLs, we can generate exact schemas.
81
+ - Write operations require SOL for transaction fees + rent.
82
+ - Always test on devnet first: `new SATPSDK({ rpcUrl: 'https://api.devnet.solana.com' })`
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@brainai/satp-client",
3
+ "version": "2.0.0",
4
+ "description": "SATP v2 Client SDK — Solana Agent Token Protocol (Identity, Reviews, Reputation, Attestations, Validation)",
5
+ "main": "src/index.js",
6
+ "files": [
7
+ "src/",
8
+ "README.md"
9
+ ],
10
+ "scripts": {
11
+ "test": "node test.js"
12
+ },
13
+ "keywords": [
14
+ "solana",
15
+ "satp",
16
+ "agent",
17
+ "identity",
18
+ "reputation",
19
+ "blockchain",
20
+ "web3"
21
+ ],
22
+ "author": "brainAI",
23
+ "license": "MIT",
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "https://github.com/brainai-dev/satp-client"
27
+ },
28
+ "homepage": "https://agentfolio.bot",
29
+ "dependencies": {
30
+ "@solana/web3.js": "^1.98.4",
31
+ "borsh": "^2.0.0",
32
+ "bs58": "^6.0.0"
33
+ }
34
+ }
@@ -0,0 +1,67 @@
1
+ const { PublicKey } = require('@solana/web3.js');
2
+
3
+ // SATP v2 Program IDs — Devnet
4
+ const DEVNET_PROGRAM_IDS = {
5
+ IDENTITY: new PublicKey('EJtQh4Gyg88zXvSmFpxYkkeZsPwTsjfm4LvjmPQX1FD3'),
6
+ REVIEWS: new PublicKey('D8HsSpK3JtAN7tVcA1yfgxScju7KcG6skEfaShSKojki'),
7
+ REPUTATION: new PublicKey('4y4W2Mdfpu91C4iVowiDyJTmdKSjo8bmSDQrX2c84WQF'),
8
+ ATTESTATIONS: new PublicKey('9xT3eNcndkmnqZtJqDQ1ggckHK7Dxo5EsAt5mHqsPBhP'),
9
+ VALIDATION: new PublicKey('8jLaqodAzfM7oCxP7aedFeszeNjnJ5ik56dzhDU2HQgc'),
10
+ };
11
+
12
+ // SATP v2 Program IDs — Mainnet
13
+ const MAINNET_PROGRAM_IDS = {
14
+ IDENTITY: new PublicKey('97yL33fcu6iWT2TdERS5HeqrMSGiUnxuy6nUcTrKieSq'),
15
+ REVIEWS: new PublicKey('Ge1sD2qwmH8QaaKCPZzZERvsFXNVMvKbAgTp2p17yjLK'),
16
+ REPUTATION: new PublicKey('C9ogv8TBrvFy4pLKDoGQg9B73Q5rKPPsQ4kzkcDk6Jd'),
17
+ ATTESTATIONS: new PublicKey('ENvaD19QzwWWMJFu5r5xJ9SmHqWN6GvyzxACRejqbdug'),
18
+ VALIDATION: new PublicKey('9p795d2j3eGqzborG2AncucWBaU6PieKxmhKVroV3LNh'),
19
+ };
20
+
21
+ const MAINNET_RPC = 'https://api.mainnet-beta.solana.com';
22
+ const DEVNET_RPC = 'https://api.devnet.solana.com';
23
+
24
+ // PDA seeds (must match on-chain programs)
25
+ const IDENTITY_SEED = 'identity';
26
+ const REPUTATION_AUTHORITY_SEED = 'reputation_authority';
27
+ const VALIDATION_AUTHORITY_SEED = 'validation_authority';
28
+ const REVIEW_COUNTER_SEED = 'review_counter';
29
+ const MINT_TRACKER_SEED = 'mint_tracker';
30
+ const REVIEWS_AUTHORITY_SEED = 'reviews_authority';
31
+ const ATTESTATION_SEED = 'attestation';
32
+ const REVIEW_SEED = 'review';
33
+
34
+ /**
35
+ * Get program IDs for a given network.
36
+ * @param {'mainnet'|'devnet'} network
37
+ * @returns {object} Program ID map
38
+ */
39
+ function getProgramIds(network = 'devnet') {
40
+ return network === 'mainnet' ? MAINNET_PROGRAM_IDS : DEVNET_PROGRAM_IDS;
41
+ }
42
+
43
+ /**
44
+ * Get RPC URL for a given network.
45
+ * @param {'mainnet'|'devnet'} network
46
+ * @returns {string} RPC URL
47
+ */
48
+ function getRpcUrl(network = 'devnet') {
49
+ return network === 'mainnet' ? MAINNET_RPC : DEVNET_RPC;
50
+ }
51
+
52
+ module.exports = {
53
+ DEVNET_PROGRAM_IDS,
54
+ MAINNET_PROGRAM_IDS,
55
+ getProgramIds,
56
+ getRpcUrl,
57
+ MAINNET_RPC,
58
+ DEVNET_RPC,
59
+ IDENTITY_SEED,
60
+ REPUTATION_AUTHORITY_SEED,
61
+ VALIDATION_AUTHORITY_SEED,
62
+ REVIEW_COUNTER_SEED,
63
+ MINT_TRACKER_SEED,
64
+ REVIEWS_AUTHORITY_SEED,
65
+ ATTESTATION_SEED,
66
+ REVIEW_SEED,
67
+ };
package/src/index.js ADDED
@@ -0,0 +1,323 @@
1
+ const {
2
+ Connection,
3
+ PublicKey,
4
+ Transaction,
5
+ TransactionInstruction,
6
+ SystemProgram,
7
+ } = require('@solana/web3.js');
8
+ const borsh = require('borsh');
9
+ const { getProgramIds, getRpcUrl } = require('./constants');
10
+ const {
11
+ getIdentityPDA,
12
+ getReputationAuthorityPDA,
13
+ getValidationAuthorityPDA,
14
+ getReviewCounterPDA,
15
+ getMintTrackerPDA,
16
+ getReviewsAuthorityPDA,
17
+ getReviewPDA,
18
+ getReviewAttestationPDA,
19
+ } = require('./pda');
20
+ const {
21
+ IdentityAccount, IDENTITY_SCHEMA,
22
+ ReputationAccount, REPUTATION_SCHEMA,
23
+ } = require('./schema');
24
+ const crypto = require('crypto');
25
+
26
+ /**
27
+ * Compute Anchor instruction discriminator.
28
+ * @param {string} ixName - e.g. "create_identity"
29
+ * @returns {Buffer} 8-byte discriminator
30
+ */
31
+ function anchorDiscriminator(ixName) {
32
+ return crypto.createHash('sha256')
33
+ .update(`global:${ixName}`)
34
+ .digest()
35
+ .slice(0, 8);
36
+ }
37
+
38
+ class SATPSDK {
39
+ /**
40
+ * @param {object} opts
41
+ * @param {'mainnet'|'devnet'} [opts.network='devnet'] - Network selection
42
+ * @param {string} [opts.rpcUrl] - Custom RPC endpoint (overrides network default)
43
+ * @param {string} [opts.commitment='confirmed'] - Commitment level
44
+ */
45
+ constructor(opts = {}) {
46
+ this.network = opts.network || 'devnet';
47
+ this.rpcUrl = opts.rpcUrl || getRpcUrl(this.network);
48
+ this.commitment = opts.commitment || 'confirmed';
49
+ this.connection = new Connection(this.rpcUrl, this.commitment);
50
+ this.programIds = getProgramIds(this.network);
51
+ }
52
+
53
+ // ─── Identity ──────────────────────────────────────────
54
+
55
+ /**
56
+ * Build a createIdentity transaction.
57
+ * @param {PublicKey|string} wallet - Owner wallet (signer)
58
+ * @param {string} agentName
59
+ * @param {string|object} metadata - JSON string or object
60
+ * @returns {{ transaction: Transaction, identityPDA: PublicKey }}
61
+ */
62
+ async buildCreateIdentity(wallet, agentName, metadata) {
63
+ const walletKey = new PublicKey(wallet);
64
+ const [identityPDA] = getIdentityPDA(walletKey, this.network);
65
+ const metaStr = typeof metadata === 'object' ? JSON.stringify(metadata) : metadata;
66
+
67
+ const disc = anchorDiscriminator('create_identity');
68
+ const nameBytes = Buffer.from(agentName, 'utf8');
69
+ const metaBytes = Buffer.from(metaStr, 'utf8');
70
+
71
+ const data = Buffer.concat([
72
+ disc,
73
+ Buffer.from(new Uint32Array([nameBytes.length]).buffer),
74
+ nameBytes,
75
+ Buffer.from(new Uint32Array([metaBytes.length]).buffer),
76
+ metaBytes,
77
+ ]);
78
+
79
+ const ix = new TransactionInstruction({
80
+ programId: this.programIds.IDENTITY,
81
+ keys: [
82
+ { pubkey: walletKey, isSigner: true, isWritable: true },
83
+ { pubkey: identityPDA, isSigner: false, isWritable: true },
84
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
85
+ ],
86
+ data,
87
+ });
88
+
89
+ const tx = new Transaction().add(ix);
90
+ tx.feePayer = walletKey;
91
+ tx.recentBlockhash = (await this.connection.getLatestBlockhash()).blockhash;
92
+
93
+ return { transaction: tx, identityPDA };
94
+ }
95
+
96
+ /**
97
+ * Create an identity on-chain (requires a Keypair signer).
98
+ */
99
+ async createIdentity(signer, agentName, metadata) {
100
+ const { transaction } = await this.buildCreateIdentity(signer.publicKey, agentName, metadata);
101
+ const sig = await this.connection.sendTransaction(transaction, [signer]);
102
+ await this.connection.confirmTransaction(sig, this.commitment);
103
+ return sig;
104
+ }
105
+
106
+ /**
107
+ * Fetch identity data for a wallet. Returns null if not found.
108
+ */
109
+ async getIdentity(wallet) {
110
+ const [pda] = getIdentityPDA(new PublicKey(wallet), this.network);
111
+ const acct = await this.connection.getAccountInfo(pda);
112
+ if (!acct) return null;
113
+
114
+ try {
115
+ const decoded = borsh.deserialize(IDENTITY_SCHEMA, IdentityAccount, acct.data);
116
+ return {
117
+ owner: new PublicKey(decoded.owner).toBase58(),
118
+ agentName: decoded.agentName,
119
+ metadata: decoded.metadata,
120
+ createdAt: Number(decoded.createdAt),
121
+ updatedAt: Number(decoded.updatedAt),
122
+ pda: pda.toBase58(),
123
+ };
124
+ } catch (e) {
125
+ return { pda: pda.toBase58(), raw: acct.data.toString('hex'), error: e.message };
126
+ }
127
+ }
128
+
129
+ // ─── Reputation (v2 CPI-based recompute) ───────────────
130
+
131
+ /**
132
+ * Build a recomputeReputation transaction.
133
+ * This is permissionless — anyone can call it to recompute an agent's score.
134
+ * The Reputation program CPIs into Identity to update the score.
135
+ *
136
+ * @param {PublicKey|string} agentWallet - Agent whose reputation to recompute
137
+ * @param {PublicKey|string} payer - Transaction fee payer (signer)
138
+ * @returns {{ transaction: Transaction }}
139
+ */
140
+ async buildRecomputeReputation(agentWallet, payer) {
141
+ const agentKey = new PublicKey(agentWallet);
142
+ const payerKey = new PublicKey(payer);
143
+ const [identityPDA] = getIdentityPDA(agentKey, this.network);
144
+ const [repAuthority] = getReputationAuthorityPDA(this.network);
145
+ const [reviewCounter] = getReviewCounterPDA(agentKey, this.network);
146
+
147
+ const disc = anchorDiscriminator('recompute_reputation');
148
+
149
+ const ix = new TransactionInstruction({
150
+ programId: this.programIds.REPUTATION,
151
+ keys: [
152
+ { pubkey: payerKey, isSigner: true, isWritable: true },
153
+ { pubkey: identityPDA, isSigner: false, isWritable: true },
154
+ { pubkey: reviewCounter, isSigner: false, isWritable: false },
155
+ { pubkey: repAuthority, isSigner: false, isWritable: false },
156
+ { pubkey: this.programIds.IDENTITY, isSigner: false, isWritable: false },
157
+ ],
158
+ data: disc,
159
+ });
160
+
161
+ const tx = new Transaction().add(ix);
162
+ tx.feePayer = payerKey;
163
+ tx.recentBlockhash = (await this.connection.getLatestBlockhash()).blockhash;
164
+
165
+ return { transaction: tx };
166
+ }
167
+
168
+ /**
169
+ * Trigger reputation recompute (permissionless).
170
+ */
171
+ async recomputeReputation(signerKeypair, agentWallet) {
172
+ const { transaction } = await this.buildRecomputeReputation(agentWallet, signerKeypair.publicKey);
173
+ const sig = await this.connection.sendTransaction(transaction, [signerKeypair]);
174
+ await this.connection.confirmTransaction(sig, this.commitment);
175
+ return sig;
176
+ }
177
+
178
+ /**
179
+ * Fetch reputation data for a wallet.
180
+ */
181
+ async getReputation(wallet) {
182
+ const [pda] = getIdentityPDA(new PublicKey(wallet), this.network);
183
+ const acct = await this.connection.getAccountInfo(pda);
184
+ if (!acct) return null;
185
+
186
+ try {
187
+ const decoded = borsh.deserialize(IDENTITY_SCHEMA, IdentityAccount, acct.data);
188
+ return {
189
+ owner: new PublicKey(decoded.owner).toBase58(),
190
+ agentName: decoded.agentName,
191
+ reputationScore: decoded.reputationScore || 0,
192
+ verificationLevel: decoded.verificationLevel || 0,
193
+ pda: pda.toBase58(),
194
+ };
195
+ } catch (e) {
196
+ return { pda: pda.toBase58(), raw: acct.data.toString('hex'), error: e.message };
197
+ }
198
+ }
199
+
200
+ // ─── Validation (v2 CPI-based recompute) ───────────────
201
+
202
+ /**
203
+ * Build a recomputeLevel transaction.
204
+ * Permissionless — recomputes verification level based on attestation count.
205
+ *
206
+ * @param {PublicKey|string} agentWallet - Agent whose level to recompute
207
+ * @param {PublicKey|string} payer - Transaction fee payer
208
+ * @returns {{ transaction: Transaction }}
209
+ */
210
+ async buildRecomputeLevel(agentWallet, payer) {
211
+ const agentKey = new PublicKey(agentWallet);
212
+ const payerKey = new PublicKey(payer);
213
+ const [identityPDA] = getIdentityPDA(agentKey, this.network);
214
+ const [valAuthority] = getValidationAuthorityPDA(this.network);
215
+
216
+ const disc = anchorDiscriminator('recompute_level');
217
+
218
+ const ix = new TransactionInstruction({
219
+ programId: this.programIds.VALIDATION,
220
+ keys: [
221
+ { pubkey: payerKey, isSigner: true, isWritable: true },
222
+ { pubkey: identityPDA, isSigner: false, isWritable: true },
223
+ { pubkey: valAuthority, isSigner: false, isWritable: false },
224
+ { pubkey: this.programIds.IDENTITY, isSigner: false, isWritable: false },
225
+ ],
226
+ data: disc,
227
+ });
228
+
229
+ const tx = new Transaction().add(ix);
230
+ tx.feePayer = payerKey;
231
+ tx.recentBlockhash = (await this.connection.getLatestBlockhash()).blockhash;
232
+
233
+ return { transaction: tx };
234
+ }
235
+
236
+ /**
237
+ * Trigger verification level recompute (permissionless).
238
+ */
239
+ async recomputeLevel(signerKeypair, agentWallet) {
240
+ const { transaction } = await this.buildRecomputeLevel(agentWallet, signerKeypair.publicKey);
241
+ const sig = await this.connection.sendTransaction(transaction, [signerKeypair]);
242
+ await this.connection.confirmTransaction(sig, this.commitment);
243
+ return sig;
244
+ }
245
+
246
+ // ─── MintTracker ───────────────────────────────────────
247
+
248
+ /**
249
+ * Build initMintTracker transaction.
250
+ * @param {PublicKey|string} wallet - Identity owner
251
+ * @returns {{ transaction: Transaction, mintTrackerPDA: PublicKey }}
252
+ */
253
+ async buildInitMintTracker(wallet) {
254
+ const walletKey = new PublicKey(wallet);
255
+ const [identityPDA] = getIdentityPDA(walletKey, this.network);
256
+ const [mintTrackerPDA] = getMintTrackerPDA(identityPDA, this.network);
257
+
258
+ const disc = anchorDiscriminator('init_mint_tracker');
259
+
260
+ const ix = new TransactionInstruction({
261
+ programId: this.programIds.IDENTITY,
262
+ keys: [
263
+ { pubkey: walletKey, isSigner: true, isWritable: true },
264
+ { pubkey: identityPDA, isSigner: false, isWritable: false },
265
+ { pubkey: mintTrackerPDA, isSigner: false, isWritable: true },
266
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
267
+ ],
268
+ data: disc,
269
+ });
270
+
271
+ const tx = new Transaction().add(ix);
272
+ tx.feePayer = walletKey;
273
+ tx.recentBlockhash = (await this.connection.getLatestBlockhash()).blockhash;
274
+
275
+ return { transaction: tx, mintTrackerPDA };
276
+ }
277
+
278
+ // ─── Verification ──────────────────────────────────────
279
+
280
+ /**
281
+ * Check if a wallet has a registered SATP identity.
282
+ */
283
+ async verifyAgent(wallet) {
284
+ const identity = await this.getIdentity(wallet);
285
+ return identity !== null && !identity.error;
286
+ }
287
+
288
+ // ─── Utility ───────────────────────────────────────────
289
+
290
+ /**
291
+ * Derive all PDAs for a wallet without RPC calls.
292
+ */
293
+ getPDAs(wallet) {
294
+ const walletKey = new PublicKey(wallet);
295
+ const [identityPDA] = getIdentityPDA(walletKey, this.network);
296
+ const [reviewCounter] = getReviewCounterPDA(walletKey, this.network);
297
+ const [mintTracker] = getMintTrackerPDA(identityPDA, this.network);
298
+ const [repAuthority] = getReputationAuthorityPDA(this.network);
299
+ const [valAuthority] = getValidationAuthorityPDA(this.network);
300
+
301
+ return {
302
+ identity: identityPDA.toBase58(),
303
+ reviewCounter: reviewCounter.toBase58(),
304
+ mintTracker: mintTracker.toBase58(),
305
+ reputationAuthority: repAuthority.toBase58(),
306
+ validationAuthority: valAuthority.toBase58(),
307
+ };
308
+ }
309
+ }
310
+
311
+ module.exports = {
312
+ SATPSDK,
313
+ getProgramIds,
314
+ getIdentityPDA,
315
+ getReputationAuthorityPDA,
316
+ getValidationAuthorityPDA,
317
+ getReviewCounterPDA,
318
+ getMintTrackerPDA,
319
+ getReviewsAuthorityPDA,
320
+ getReviewPDA,
321
+ getReviewAttestationPDA,
322
+ anchorDiscriminator,
323
+ };
package/src/pda.js ADDED
@@ -0,0 +1,148 @@
1
+ const { PublicKey } = require('@solana/web3.js');
2
+ const {
3
+ getProgramIds,
4
+ IDENTITY_SEED,
5
+ REPUTATION_AUTHORITY_SEED,
6
+ VALIDATION_AUTHORITY_SEED,
7
+ REVIEW_COUNTER_SEED,
8
+ MINT_TRACKER_SEED,
9
+ REVIEWS_AUTHORITY_SEED,
10
+ ATTESTATION_SEED,
11
+ REVIEW_SEED,
12
+ } = require('./constants');
13
+
14
+ /**
15
+ * Derive the Identity PDA for a wallet.
16
+ * Seeds: ["identity", wallet_pubkey]
17
+ * @param {PublicKey|string} wallet
18
+ * @param {'mainnet'|'devnet'} network
19
+ */
20
+ function getIdentityPDA(wallet, network = 'devnet') {
21
+ const walletKey = new PublicKey(wallet);
22
+ const programIds = getProgramIds(network);
23
+ return PublicKey.findProgramAddressSync(
24
+ [Buffer.from(IDENTITY_SEED), walletKey.toBuffer()],
25
+ programIds.IDENTITY
26
+ );
27
+ }
28
+
29
+ /**
30
+ * Derive the Reputation Authority PDA (program signer for CPI).
31
+ * Seeds: ["reputation_authority"]
32
+ * @param {'mainnet'|'devnet'} network
33
+ */
34
+ function getReputationAuthorityPDA(network = 'devnet') {
35
+ const programIds = getProgramIds(network);
36
+ return PublicKey.findProgramAddressSync(
37
+ [Buffer.from(REPUTATION_AUTHORITY_SEED)],
38
+ programIds.REPUTATION
39
+ );
40
+ }
41
+
42
+ /**
43
+ * Derive the Validation Authority PDA (program signer for CPI).
44
+ * Seeds: ["validation_authority"]
45
+ * @param {'mainnet'|'devnet'} network
46
+ */
47
+ function getValidationAuthorityPDA(network = 'devnet') {
48
+ const programIds = getProgramIds(network);
49
+ return PublicKey.findProgramAddressSync(
50
+ [Buffer.from(VALIDATION_AUTHORITY_SEED)],
51
+ programIds.VALIDATION
52
+ );
53
+ }
54
+
55
+ /**
56
+ * Derive the Review Counter PDA for an agent.
57
+ * Seeds: ["review_counter", agent_id]
58
+ * @param {PublicKey|string} agentId
59
+ * @param {'mainnet'|'devnet'} network
60
+ */
61
+ function getReviewCounterPDA(agentId, network = 'devnet') {
62
+ const agentKey = new PublicKey(agentId);
63
+ const programIds = getProgramIds(network);
64
+ return PublicKey.findProgramAddressSync(
65
+ [Buffer.from(REVIEW_COUNTER_SEED), agentKey.toBuffer()],
66
+ programIds.REVIEWS
67
+ );
68
+ }
69
+
70
+ /**
71
+ * Derive the MintTracker PDA for an identity.
72
+ * Seeds: ["mint_tracker", identity_pda]
73
+ * @param {PublicKey|string} identityPDA
74
+ * @param {'mainnet'|'devnet'} network
75
+ */
76
+ function getMintTrackerPDA(identityPDA, network = 'devnet') {
77
+ const identityKey = new PublicKey(identityPDA);
78
+ const programIds = getProgramIds(network);
79
+ return PublicKey.findProgramAddressSync(
80
+ [Buffer.from(MINT_TRACKER_SEED), identityKey.toBuffer()],
81
+ programIds.IDENTITY
82
+ );
83
+ }
84
+
85
+ /**
86
+ * Derive the Reviews Authority PDA (program signer for CPI into Attestations).
87
+ * Seeds: ["reviews_authority"]
88
+ * @param {'mainnet'|'devnet'} network
89
+ */
90
+ function getReviewsAuthorityPDA(network = 'devnet') {
91
+ const programIds = getProgramIds(network);
92
+ return PublicKey.findProgramAddressSync(
93
+ [Buffer.from(REVIEWS_AUTHORITY_SEED)],
94
+ programIds.REVIEWS
95
+ );
96
+ }
97
+
98
+ /**
99
+ * Derive the Review PDA for a specific reviewer + agent pair.
100
+ * Seeds: ["review", agent_id, reviewer]
101
+ * @param {PublicKey|string} agentId
102
+ * @param {PublicKey|string} reviewer
103
+ * @param {'mainnet'|'devnet'} network
104
+ */
105
+ function getReviewPDA(agentId, reviewer, network = 'devnet') {
106
+ const agentKey = new PublicKey(agentId);
107
+ const reviewerKey = new PublicKey(reviewer);
108
+ const programIds = getProgramIds(network);
109
+ return PublicKey.findProgramAddressSync(
110
+ [Buffer.from(REVIEW_SEED), agentKey.toBuffer(), reviewerKey.toBuffer()],
111
+ programIds.REVIEWS
112
+ );
113
+ }
114
+
115
+ /**
116
+ * Derive the Review Attestation PDA (auto-created via CPI when a review is submitted).
117
+ * Seeds: ["attestation", agent_id, reviews_authority, "review", reviewer]
118
+ * @param {PublicKey|string} agentId
119
+ * @param {PublicKey} reviewsAuthority - Use getReviewsAuthorityPDA() to derive
120
+ * @param {PublicKey|string} reviewer
121
+ * @param {'mainnet'|'devnet'} network
122
+ */
123
+ function getReviewAttestationPDA(agentId, reviewsAuthority, reviewer, network = 'devnet') {
124
+ const agentKey = new PublicKey(agentId);
125
+ const reviewerKey = new PublicKey(reviewer);
126
+ const programIds = getProgramIds(network);
127
+ return PublicKey.findProgramAddressSync(
128
+ [
129
+ Buffer.from(ATTESTATION_SEED),
130
+ agentKey.toBuffer(),
131
+ reviewsAuthority.toBuffer(),
132
+ Buffer.from(REVIEW_SEED),
133
+ reviewerKey.toBuffer(),
134
+ ],
135
+ programIds.ATTESTATIONS
136
+ );
137
+ }
138
+
139
+ module.exports = {
140
+ getIdentityPDA,
141
+ getReputationAuthorityPDA,
142
+ getValidationAuthorityPDA,
143
+ getReviewCounterPDA,
144
+ getMintTrackerPDA,
145
+ getReviewsAuthorityPDA,
146
+ getReviewPDA,
147
+ getReviewAttestationPDA,
148
+ };
package/src/schema.js ADDED
@@ -0,0 +1,59 @@
1
+ const borsh = require('borsh');
2
+
3
+ // ---- Identity Account Schema ----
4
+ class IdentityAccount {
5
+ constructor(fields) {
6
+ this.discriminator = fields.discriminator; // 8 bytes (Anchor)
7
+ this.owner = fields.owner; // 32 bytes pubkey
8
+ this.agentName = fields.agentName; // string
9
+ this.metadata = fields.metadata; // string (JSON)
10
+ this.createdAt = fields.createdAt; // i64 timestamp
11
+ this.updatedAt = fields.updatedAt; // i64 timestamp
12
+ this.bump = fields.bump; // u8
13
+ }
14
+ }
15
+
16
+ const IDENTITY_SCHEMA = new Map([
17
+ [IdentityAccount, {
18
+ kind: 'struct',
19
+ fields: [
20
+ ['discriminator', [8]],
21
+ ['owner', [32]],
22
+ ['agentName', 'string'],
23
+ ['metadata', 'string'],
24
+ ['createdAt', 'u64'],
25
+ ['updatedAt', 'u64'],
26
+ ['bump', 'u8'],
27
+ ],
28
+ }],
29
+ ]);
30
+
31
+ // ---- Reputation Account Schema ----
32
+ class ReputationAccount {
33
+ constructor(fields) {
34
+ this.discriminator = fields.discriminator;
35
+ this.owner = fields.owner;
36
+ this.score = fields.score; // u64
37
+ this.endorsements = fields.endorsements; // u32 count
38
+ this.lastEndorser = fields.lastEndorser; // 32 bytes pubkey
39
+ this.updatedAt = fields.updatedAt;
40
+ this.bump = fields.bump;
41
+ }
42
+ }
43
+
44
+ const REPUTATION_SCHEMA = new Map([
45
+ [ReputationAccount, {
46
+ kind: 'struct',
47
+ fields: [
48
+ ['discriminator', [8]],
49
+ ['owner', [32]],
50
+ ['score', 'u64'],
51
+ ['endorsements', 'u32'],
52
+ ['lastEndorser', [32]],
53
+ ['updatedAt', 'u64'],
54
+ ['bump', 'u8'],
55
+ ],
56
+ }],
57
+ ]);
58
+
59
+ module.exports = { IdentityAccount, IDENTITY_SCHEMA, ReputationAccount, REPUTATION_SCHEMA };