@brainai/satp-client 2.0.0 → 2.0.2

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 CHANGED
@@ -1,82 +1,560 @@
1
- # SATP JavaScript SDK
1
+ # SATP V3 SDK - `@brainai/satp-client`
2
2
 
3
- Lightweight SDK for interacting with SATP (Solana Agent Token Protocol) programs on Solana.
3
+ **Solana Agent Token Protocol** - JavaScript/TypeScript SDK for interacting with the SATP V3 devnet programs.
4
4
 
5
- ## Install
5
+ Current stable npm package: **@brainai/satp-client@2.0.1** | reviewed rc artifact: **@brainai/satp-client@2.0.2-rc.0** | Programs: **6**
6
+
7
+ ## Installation
8
+
9
+ Choose stable, rc, or Git based on what the consumer needs to prove:
10
+
11
+ | Channel | Use when | Command |
12
+ | --- | --- | --- |
13
+ | Stable npm | Default production-style consumption of the stable public package. | `npm install @brainai/satp-client@2.0.1` |
14
+ | Release candidate npm | Validating the reviewed rc package before promotion or producing reproducible rc manifests. | `npm install @brainai/satp-client@2.0.2-rc.0` |
15
+ | Release candidate tag | Quick rc opt-in where a moving dist-tag is acceptable. | `npm install @brainai/satp-client@rc` |
16
+ | Reviewed Git commit | PR coordination or source-review installs tied to an exact SATP commit. | `npm install git+https://github.com/brainAI-bot/satp.git#<SATP_COMMIT>` |
17
+
18
+ The npm `latest` tag still resolves to `@brainai/satp-client@2.0.1`.
19
+ Historical rc-tag readback may still show the older `0.1.0-rc.0` package until
20
+ the rc channel is promoted. The reviewed RC-S6 artifact in this source tree is
21
+ `@brainai/satp-client@2.0.2-rc.0`; downstream apps that need reproducible
22
+ manifests should pin that exact version after promotion instead of relying on
23
+ the moving `@rc` tag.
24
+
25
+ For stable consumer installs, pin the current published npm package:
26
+
27
+ ```bash
28
+ npm install @brainai/satp-client@2.0.1
29
+ ```
30
+
31
+ For exact rc validation:
32
+
33
+ ```bash
34
+ npm install @brainai/satp-client@2.0.2-rc.0
35
+ ```
36
+
37
+ For short-lived rc opt-in:
38
+
39
+ ```bash
40
+ npm install @brainai/satp-client@rc
41
+ ```
42
+
43
+ For branch-only development or PR review, pin an explicit SATP Git commit:
6
44
 
7
45
  ```bash
8
- cd satp-sdk && npm install
46
+ npm install git+https://github.com/brainAI-bot/satp.git#<SATP_COMMIT>
9
47
  ```
10
48
 
49
+ The old `0.0.0-extraction` label was extraction-branch metadata and is not the
50
+ current consumer package. Do not treat branch-only Git installs as npm latest.
51
+
52
+ Mainnet program IDs are intentionally not enabled in this release candidate.
53
+ Constructors and helpers fail closed for `network: 'mainnet'` until an approved
54
+ mainnet decision packet provides production program IDs.
55
+
56
+ **Runtime dependency:** `@solana/web3.js ^1.98.4`
57
+
11
58
  ## Quick Start
12
59
 
13
- ```js
14
- const { SATPSDK } = require('./src');
60
+ ```javascript
61
+ const { SATPV3SDK } = require('@brainai/satp-client');
62
+
63
+ // Initialize (devnet by default)
64
+ const sdk = new SATPV3SDK({ network: 'devnet' });
65
+
66
+ // Check if an agent has an identity
67
+ const exists = await sdk.hasIdentity('brainChain');
68
+ console.log(exists); // true
69
+
70
+ // Read a Genesis Record
71
+ const record = await sdk.getGenesisRecord('brainChain');
72
+ console.log(record.agentName, record.category, record.isActive);
73
+
74
+ // Build a transaction (unsigned — sign with your wallet)
75
+ const tx = await sdk.buildCreateIdentity(creatorPubkey, 'myAgent', {
76
+ agentName: 'My Agent',
77
+ description: 'An AI agent on Solana',
78
+ category: 'assistant',
79
+ capabilities: ['chat', 'code'],
80
+ metadataUri: 'https://example.com/meta.json',
81
+ });
82
+ // Sign and send tx with your wallet...
83
+ ```
84
+
85
+ ## Architecture
86
+
87
+ ```
88
+ ┌─────────────────────────────────────────────────────────────────┐
89
+ │ SATP V3 SDK │
90
+ ├─────────────┬──────────────┬──────────────┬─────────────────────┤
91
+ │ Identity │ Reviews │ Attestations │ Escrow │
92
+ │ (20 methods)│ (7 methods) │ (3 methods) │ (10 methods) │
93
+ ├─────────────┼──────────────┼──────────────┤ │
94
+ │ Reputation │ Validation │ Migration │ │
95
+ │ (1 method) │ (1 method) │ (1 method) │ │
96
+ ├─────────────┴──────────────┴──────────────┴─────────────────────┤
97
+ │ PDA Derivation │ Borsh Serialization │ RPC Helpers │
98
+ └─────────────────┴───────────────────────┴───────────────────────┘
99
+ ```
100
+
101
+ ## Programs & Program IDs
102
+
103
+ | Program | Devnet | Description |
104
+ |---------|--------|-------------|
105
+ | `identity_v3` | `GTppU4E44BqXTQgbqMZ68ozFzhP1TLty3EGnzzjtNZfG` | Agent identity, names, wallets, face/birth |
106
+ | `reviews_v3` | `r9XX4frcqxxAZ6Au9V5PA3EAxs1zoNckqLLmoSRcNr4` | Peer reviews with 1-5 star ratings |
107
+ | `attestations_v3` | `6Xd1dAQJPvQRJ4Ntr6LtPTjDjPUZ8nfnmYLZaZ2DtrdD` | Third-party attestations & proofs |
108
+ | `reputation_v3` | `2Lz7KzMvKdrGeAuS8WPHu7jK2yScrnKVgacpYVEuDjkJ` | Weighted reputation scoring (CPI → identity) |
109
+ | `validation_v3` | `6rYRiCYidJYV7QvKrzKGgNu4oMh6BAvynked69R7xMbV` | Validation level computation (CPI → identity) |
110
+ | `escrow_v3` | `HXCUWKR2NvRcZ7rNAJHwPcH6QAAWaLR4bRFbfyuDND6C` | SOL escrow for agent jobs |
111
+
112
+ ## API Reference
113
+
114
+ ### Read-only Trust Packet Helpers
115
+
116
+ `buildSatpTrustPacket(opts)` creates a deterministic, offline trust packet for
117
+ consumer preflight and release-packet review. It uses the same inputs as
118
+ `prepareIdentityAttestationRequest`, then includes the derived program IDs,
119
+ Genesis PDA, attestation PDA, request hash, and the unsigned request object.
120
+ The packet is intentionally read-only: `flags.signingRequired`,
121
+ `flags.transactionRequired`, `flags.writesRequired`, and
122
+ `flags.livePaymentRequired` are all `false`; `instructions` and `signers`
123
+ are empty; and `transaction` is `null`.
124
+
125
+ ```javascript
126
+ const {
127
+ buildSatpTrustPacket,
128
+ validateSatpTrustPacket,
129
+ } = require('@brainai/satp-client');
130
+
131
+ const trustPacket = buildSatpTrustPacket({
132
+ subjectWallet: '11111111111111111111111111111111',
133
+ agentId: 'brainChain',
134
+ claimType: 'identity',
135
+ metadataHash: '93d122f8879fe87c186c10a00db8fbc80a73cecd2ede44b9ffa6410be3c2b805',
136
+ network: 'devnet',
137
+ });
138
+
139
+ const validation = validateSatpTrustPacket(trustPacket);
140
+ if (!validation.ok) throw new Error(validation.errors.join('; '));
141
+ ```
142
+
143
+ `validateSatpTrustPacket(packet)` returns `{ ok, errors }`. Validation requires
144
+ `packetType: 'satp-trust-packet'` and
145
+ `mode: 'offline-readonly-trust-packet'`, rejects changed read-only flags, and
146
+ re-derives the expected packet so tampered PDA, program, request, or hash fields
147
+ surface as explicit errors.
148
+
149
+ ### x402 Discovery Evidence Lookup Helpers
150
+
151
+ `parseX402DiscoveryMetadata(input)`, `buildX402EvidenceLookup(input, opts)`,
152
+ and `buildRuntimePolicyActionDescriptorFromX402Discovery(input, opts)` map x402
153
+ discovery metadata into SATP runtime policy evidence lookup data. The helpers are
154
+ read-only: x402 payment metadata can identify where evidence may be fetched, but
155
+ it is discovery/evidence lookup only and never authorizes SATP action execution,
156
+ spending, live payment, signing, transactions, or host policy bypass.
157
+
158
+ Run the offline example:
159
+
160
+ ```bash
161
+ node packages/satp-client/examples/x402-discovery-evidence-lookup.js
162
+ ```
163
+
164
+ The example parses discovery metadata, builds an evidence lookup descriptor, and
165
+ builds a runtime policy action descriptor. It asserts
166
+ `X402_PAYMENT_IS_NOT_ACTION_AUTHORIZATION` plus
167
+ `paymentAuthorization: false`, `actionAuthorization: false`,
168
+ `spendAuthorized: false`, and `livePaymentRequired: false`.
169
+
170
+ ### Wallet-Control Challenge Helpers
171
+
172
+ `buildWalletControlChallenge(opts)` creates a canonical, offline challenge that
173
+ binds an agent ID to a Solana wallet. It derives the SATP V3 Genesis PDA and
174
+ linked-wallet PDA from `agentId`, `wallet`, and `network`, includes a nonce and
175
+ expiry, and returns plain JSON. It does not connect to RPC, read keypairs,
176
+ create transactions, sign, send, deploy, or mutate chain state.
177
+
178
+ `canonicalWalletControlChallenge(challenge)` returns the exact UTF-8 message a
179
+ wallet signs. `verifyWalletControlChallengeSignature(opts)` verifies a 64-byte
180
+ Ed25519 signature against the challenge wallet and fails closed for mismatched
181
+ wallets, signatures, agent IDs, PDAs, domain, audience, expiry, and replayed
182
+ nonces supplied by your replay cache.
183
+
184
+ ```javascript
185
+ const {
186
+ buildWalletControlChallenge,
187
+ canonicalWalletControlChallenge,
188
+ verifyWalletControlChallengeSignature,
189
+ } = require('@brainai/satp-client');
190
+
191
+ const challenge = buildWalletControlChallenge({
192
+ agentId: 'brainChain',
193
+ wallet: walletPublicKey,
194
+ audience: 'my-service',
195
+ nonce: crypto.randomBytes(16).toString('hex'),
196
+ });
197
+
198
+ // Ask the wallet to sign this exact canonical string.
199
+ const message = canonicalWalletControlChallenge(challenge);
200
+
201
+ const verification = verifyWalletControlChallengeSignature({
202
+ challenge,
203
+ signature,
204
+ expectedWallet: walletPublicKey,
205
+ expectedAgentId: 'brainChain',
206
+ expectedAudience: 'my-service',
207
+ usedNonces: replayCache,
208
+ });
209
+ if (!verification.ok) throw new Error(verification.errors.join('; '));
210
+ ```
211
+
212
+ ### Constructor
213
+
214
+ ```javascript
215
+ const sdk = new SATPV3SDK({ network, rpcUrl });
216
+ // network: 'devnet' (default). 'mainnet' fails closed until approved IDs exist.
217
+ // rpcUrl: optional custom RPC endpoint
218
+ ```
219
+
220
+ ---
221
+
222
+ ### Identity Methods (20)
223
+
224
+ | Method | Description |
225
+ |--------|-------------|
226
+ | `buildCreateIdentity(creator, agentId, meta)` | Create a new agent identity (Genesis Record) |
227
+ | `buildBurnToBecome(authority, agentId, faceImage, faceMint, faceBurnTx)` | Burn NFT to set agent's face (birth ritual) |
228
+ | `buildUpdateIdentity(authority, agentId, updates)` | Update mutable fields (description, capabilities, metadata) |
229
+ | `buildProposeAuthority(authority, agentId, newAuthority)` | Propose authority transfer (2-step) |
230
+ | `buildAcceptAuthority(newAuthority, agentId)` | Accept proposed authority transfer |
231
+ | `buildCancelAuthorityTransfer(authority, agentId)` | Cancel pending authority transfer |
232
+ | `buildRegisterName(authority, agentId, name)` | Register a unique name for an agent |
233
+ | `buildReleaseName(authority, agentId, name)` | Release a registered name |
234
+ | `buildLinkWallet(authority, agentId, wallet, chain, label)` | Link an external wallet to identity |
235
+ | `buildUnlinkWallet(authority, agentId, wallet)` | Unlink an external wallet |
236
+ | `buildInitMintTracker(authority, agentId)` | Initialize NFT mint tracker |
237
+ | `buildRecordMint(authority, agentId)` | Record an NFT mint event |
238
+ | `buildDeactivateIdentity(authority, agentId)` | Deactivate an identity |
239
+ | `buildReactivateIdentity(authority, agentId)` | Reactivate a deactivated identity |
240
+ | `getGenesisRecord(agentId)` | Read a Genesis Record from chain |
241
+ | `hasIdentity(agentId)` | Check if an agent has an identity |
242
+ | `getEscrowPDA(client, description, nonce)` | Derive escrow PDA (sync) |
243
+ | `buildMigrateV2ToV3(v2Authority, agentId, meta)` | Migrate from V2 to V3 identity |
244
+
245
+ #### Genesis Record Fields
246
+
247
+ ```javascript
248
+ const record = await sdk.getGenesisRecord('brainChain');
249
+ // Returns:
250
+ {
251
+ agentIdHash: string, // SHA-256 of agent_id
252
+ agentName: string, // Display name
253
+ description: string, // Agent description
254
+ category: string, // e.g. "developer", "assistant"
255
+ capabilities: string[], // e.g. ["solana", "code"]
256
+ metadataUri: string, // Off-chain metadata URL
257
+ faceImage: string, // Face image URL (after birth)
258
+ faceMint: string, // NFT mint address (after birth)
259
+ faceBurnTx: string, // Burn transaction signature
260
+ genesisRecord: number, // Unix timestamp of birth
261
+ isBorn: boolean, // Whether agent has completed birth ritual
262
+ isActive: boolean, // Whether identity is active
263
+ authority: string, // Current authority pubkey
264
+ pendingAuthority: string | null,
265
+ reputationScore: number, // CPI-updated reputation
266
+ validationLevel: number, // CPI-updated validation
267
+ createdAt: number, // Unix timestamp
268
+ updatedAt: number, // Unix timestamp
269
+ }
270
+ ```
271
+
272
+ ---
273
+
274
+ ### Reviews Methods (7)
15
275
 
16
- const sdk = new SATPSDK(); // mainnet by default
17
- // const sdk = new SATPSDK({ rpcUrl: 'https://api.devnet.solana.com' });
276
+ | Method | Description |
277
+ |--------|-------------|
278
+ | `buildInitReviewCounter(payer, agentId)` | Initialize review counter for an agent |
279
+ | `buildCreateReview(reviewer, agentId, rating, text, metadata, opts)` | Create a 1-5 star review |
280
+ | `buildCreateReviewWithSelfCheck(reviewer, agentId, rating, text, metadata)` | Create review with self-review prevention |
281
+ | `buildUpdateReview(reviewer, reviewPDA, updates)` | Update an existing review |
282
+ | `buildDeleteReview(reviewer, reviewPDA)` | Soft-delete a review |
283
+ | `getReview(agentId, reviewer)` | Read a review from chain |
284
+ | `getReviewCount(agentId)` | Get total review count for an agent |
18
285
 
19
- // Check if an agent is registered
20
- const verified = await sdk.verifyAgent('SomeWalletPubkey...');
286
+ ```javascript
287
+ // Create a review
288
+ const tx = await sdk.buildCreateReview(
289
+ reviewerPubkey,
290
+ 'brainChain', // agent being reviewed
291
+ 5, // rating (1-5)
292
+ 'Excellent Solana dev',
293
+ 'metadata',
294
+ { category: 'development' }
295
+ );
296
+ ```
297
+
298
+ ---
299
+
300
+ ### Attestations Methods (3)
301
+
302
+ | Method | Description |
303
+ |--------|-------------|
304
+ | `buildCreateAttestation(issuer, agentId, type, proofData, expiresAt)` | Issue an attestation |
305
+ | `buildVerifyAttestation(issuer, attestationPDA)` | Mark attestation as verified |
306
+ | `buildRevokeAttestation(issuer, attestationPDA)` | Revoke an attestation |
307
+
308
+ ```javascript
309
+ // Issue a KYC attestation
310
+ const tx = await sdk.buildCreateAttestation(
311
+ issuerPubkey,
312
+ 'brainChain',
313
+ 'kyc', // attestation type
314
+ 'proof-hash-here',
315
+ Math.floor(Date.now()/1000) + 86400 * 365 // expires in 1 year
316
+ );
317
+ ```
318
+
319
+ ---
320
+
321
+ ### Reputation & Validation Methods (2)
322
+
323
+ | Method | Description |
324
+ |--------|-------------|
325
+ | `buildRecomputeReputation(caller, agentId, reviewAccounts)` | Recompute reputation score from reviews (CPI → identity) |
326
+ | `buildRecomputeLevel(caller, agentId, attestationAccounts)` | Recompute validation level from attestations (CPI → identity) |
327
+
328
+ These use Cross-Program Invocation to update fields directly on the Genesis Record.
329
+
330
+ ---
331
+
332
+ ### Escrow Methods (10)
333
+
334
+ App-agnostic escrow builders for downstream applications that need unsigned
335
+ SATP escrow transactions. Product-specific marketplace records, fees, job
336
+ workflow, moderation, and display copy stay in the consuming application.
337
+
338
+ | Method | Description |
339
+ |--------|-------------|
340
+ | `buildCreateEscrow(client, agentWallet, agentId, amount, description, deadline, nonce, opts)` | Create SOL escrow for a job |
341
+ | `buildSubmitWork(agent, escrowPDA, workProof)` | Agent submits work proof |
342
+ | `buildEscrowRelease(client, agent, escrowPDA)` | Client releases full payment |
343
+ | `buildPartialRelease(client, agent, escrowPDA, amount)` | Client releases partial payment |
344
+ | `buildCancelEscrow(client, escrowPDA)` | Cancel escrow (refund client) |
345
+ | `buildRaiseDispute(signer, escrowPDA, reason)` | Raise a dispute |
346
+ | `buildResolveDispute(arbiter, agent, client, escrowPDA, agentAmt, clientAmt)` | Arbiter resolves dispute |
347
+ | `buildExtendDeadline(client, escrowPDA, newDeadline)` | Extend job deadline |
348
+ | `buildCloseEscrow(client, escrowPDA)` | Close completed/cancelled escrow (reclaim rent) |
349
+ | `getEscrow(escrowPDA)` | Read escrow state from chain |
350
+
351
+ #### Escrow Lifecycle
352
+
353
+ ```
354
+ Created → WorkSubmitted → Released (full or partial)
355
+ ↓ ↓ ↓
356
+ Cancelled Disputed Closed (rent reclaimed)
357
+
358
+ Resolved (split)
359
+
360
+ Closed
361
+ ```
362
+
363
+ ```javascript
364
+ // Create an escrow (0.5 SOL for a generic work agreement)
365
+ const tx = await sdk.buildCreateEscrow(
366
+ clientPubkey,
367
+ agentWallet,
368
+ 'brainChain',
369
+ 0.5 * 1e9, // lamports
370
+ 'Complete agreed work',
371
+ Math.floor(Date.now()/1000) + 86400 * 7, // 7 day deadline
372
+ 0, // nonce (for multiple escrows with same description)
373
+ { arbiter: arbiterPubkey }
374
+ );
375
+ ```
376
+
377
+ ---
378
+
379
+ ### PDA Helpers (exported from `v3-pda.js`)
380
+
381
+ ```javascript
382
+ const {
383
+ hashAgentId, // SHA-256 hash of agent_id string
384
+ hashName, // SHA-256 hash of name string
385
+ getGenesisPDA, // [b"genesis_record", agent_id_hash]
386
+ getNameRegistryPDA, // [b"name_registry_v3", name_hash]
387
+ getLinkedWalletPDA, // [b"linked_wallet_v3", agent_id_hash, wallet]
388
+ getV3MintTrackerPDA, // [b"mint_tracker_v3", agent_id_hash]
389
+ getV3ReviewPDA, // [b"review_v3", agent_id_hash, reviewer]
390
+ getV3ReviewCounterPDA, // [b"review_counter_v3", agent_id_hash]
391
+ getV3AttestationPDA, // [b"attestation_v3", agent_id_hash, issuer, type_hash]
392
+ getV3ReputationAuthorityPDA, // [b"reputation_authority", agent_id_hash]
393
+ getV3ValidationAuthorityPDA, // [b"validation_authority", agent_id_hash]
394
+ getV3EscrowPDA, // [b"escrow_v3", client, desc_hash, nonce_le]
395
+ getV3ProgramIds, // Returns all 6 program IDs for network
396
+ } = require('@brainai/satp-client/src/v3-pda');
397
+ ```
398
+
399
+ ---
400
+
401
+ ### Escrow SDK Utilities (exported from `v3-sdk.js`)
402
+
403
+ ```javascript
404
+ const {
405
+ deriveEscrowPda, // Derive escrow PDA from params
406
+ descriptionHash, // SHA-256 hash of description string
407
+ EscrowStatus, // Enum: { Active: 0, WorkSubmitted: 1, Released: 2, Cancelled: 3, Disputed: 4, Resolved: 5 }
408
+ escrowStatusLabel, // Convert status number to human-readable string
409
+ escrowRemaining, // Calculate remaining escrow balance
410
+ isEscrowExpired, // Check if escrow has passed deadline
411
+ } = require('@brainai/satp-client/src/v3-sdk');
412
+ ```
413
+
414
+ ## Transaction Pattern
415
+
416
+ All `build*` methods return an **unsigned** `Transaction` object. Your application is responsible for:
21
417
 
22
- // Get identity data
23
- const identity = await sdk.getIdentity('SomeWalletPubkey...');
418
+ 1. Setting `recentBlockhash` and `feePayer`
419
+ 2. Signing with the appropriate wallet
420
+ 3. Sending to the network
24
421
 
25
- // Get reputation
26
- const rep = await sdk.getReputation('SomeWalletPubkey...');
422
+ ```javascript
423
+ const tx = await sdk.buildCreateIdentity(wallet.publicKey, 'myAgent', { ... });
424
+ tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
425
+ tx.feePayer = wallet.publicKey;
426
+ tx.sign(wallet);
427
+ const sig = await connection.sendRawTransaction(tx.serialize());
428
+ await connection.confirmTransaction(sig);
429
+ ```
430
+
431
+ ## Consumer APIs
432
+
433
+ SATP core does not define or host an HTTP API. Downstream applications may wrap
434
+ the SDK with their own read APIs, but those routes are consumer-owned adapters
435
+ and must not be treated as SATP protocol authority.
27
436
 
28
- // Derive PDAs (offline, no RPC)
29
- const pdas = sdk.getPDAs('SomeWalletPubkey...');
437
+ ## Testing
438
+
439
+ ```bash
440
+ # Unit tests (101)
441
+ node test-v3.js
442
+
443
+ # Devnet integration tests (16)
444
+ node test-v3-devnet.js
445
+
446
+ # CPI integration tests (35)
447
+ cd .. && node tests/devnet-cpi-integration.js
448
+
449
+ # Release-safety defaults and mainnet fail-closed checks
450
+ node test-release-safety.js
30
451
  ```
31
452
 
32
- ## Write Operations (require a signer)
453
+ ## Network Configuration
454
+
455
+ ```javascript
456
+ // Devnet (default)
457
+ const sdk = new SATPV3SDK();
458
+
459
+ // Explicit devnet
460
+ const sdk = new SATPV3SDK({ network: 'devnet' });
461
+
462
+ // Custom RPC
463
+ const sdk = new SATPV3SDK({ rpcUrl: 'https://my-rpc.example.com' });
464
+
465
+ // Mainnet currently fails closed until approved program IDs are configured
466
+ assert.throws(() => new SATPV3SDK({ network: 'mainnet' }));
467
+ ```
468
+
469
+ ## Borsh Deserialization Helpers (v3.6.0)
470
+
471
+ Zero-dependency Borsh deserialization for all 8 SATP V3 account types. Decode raw on-chain data without the `borsh` library.
472
+
473
+ ### Supported Account Types
474
+
475
+ | Account | Program | Deserializer |
476
+ |---------|---------|-------------|
477
+ | GenesisRecord | Identity V3 | `deserializeGenesisRecord(data)` |
478
+ | LinkedWallet | Identity V3 | `deserializeLinkedWallet(data)` |
479
+ | MintTracker | Identity V3 | `deserializeMintTracker(data)` |
480
+ | NameRegistry | Identity V3 | `deserializeNameRegistry(data)` |
481
+ | Review | Reviews V3 | `deserializeReview(data)` |
482
+ | ReviewCounter | Reviews V3 | `deserializeReviewCounter(data)` |
483
+ | Attestation | Attestations V3 | `deserializeAttestation(data)` |
484
+ | EscrowV3 | Escrow V3 | `deserializeEscrowV3(data)` |
485
+
486
+ ### Usage: Typed Deserialization
33
487
 
34
488
  ```js
35
- const { Keypair } = require('@solana/web3.js');
489
+ const { deserializeGenesisRecord, deserializeAttestation } = require('@brainai/satp-client');
490
+ const { Connection, PublicKey } = require('@solana/web3.js');
491
+
492
+ const conn = new Connection('https://api.devnet.solana.com');
493
+
494
+ // Fetch raw account and deserialize
495
+ const acct = await conn.getAccountInfo(new PublicKey('...'));
496
+ const genesis = deserializeGenesisRecord(acct.data);
497
+ console.log(genesis.agentName, genesis.reputationScore, genesis.isBorn);
498
+ ```
36
499
 
37
- const signer = Keypair.fromSecretKey(/* your key */);
500
+ ### Usage: Auto-detect Account Type
38
501
 
39
- // Register identity
40
- const sig = await sdk.registerIdentity(signer, 'my-agent', { type: 'ai', version: '1.0' });
502
+ ```js
503
+ const { deserializeAccount } = require('@brainai/satp-client');
41
504
 
42
- // Add reputation (endorser signs)
43
- const sig2 = await sdk.addReputation(endorserKeypair, targetWallet, 100);
505
+ // Automatically detects type from 8-byte Anchor discriminator
506
+ const { type, data } = deserializeAccount(acct.data);
507
+ console.log(type); // "GenesisRecord" | "Attestation" | "EscrowV3" | ...
508
+ console.log(data); // Fully parsed object
44
509
  ```
45
510
 
46
- ## Transaction Builders (for wallet adapters / frontends)
511
+ ### Usage: Batch Deserialization (getProgramAccounts)
47
512
 
48
513
  ```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
514
+ const { deserializeBatch, DISCRIMINATORS } = require('@brainai/satp-client');
515
+
516
+ const accounts = await conn.getProgramAccounts(REVIEWS_PROGRAM_ID);
517
+ const reviews = deserializeBatch(accounts, 'Review');
518
+ // [{ pubkey: "...", type: "Review", data: { agentId, rating, ... } }, ...]
519
+ ```
520
+
521
+ ### Usage: BorshReader (Custom Deserialization)
522
+
523
+ ```js
524
+ const { BorshReader } = require('@brainai/satp-client');
525
+
526
+ // Low-level reader for custom account layouts
527
+ const r = new BorshReader(acct.data);
528
+ r.skipDiscriminator(); // skip 8-byte Anchor discriminator
529
+ const hash = r.readFixedBytes32(); // [u8; 32]
530
+ const name = r.readString(); // Borsh String
531
+ const items = r.readVecString(); // Vec<String>
532
+ const pk = r.readPubkeyBase58(); // Pubkey → base58
533
+ const opt = r.readOptionI64(); // Option<i64> → number | null
54
534
  ```
55
535
 
56
- ## API
536
+ ### Discriminator Utilities
57
537
 
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 |
538
+ ```js
539
+ const { isAccountType, getAccountDiscriminator, DISCRIMINATORS } = require('@brainai/satp-client');
540
+
541
+ // Check account type before deserializing
542
+ if (isAccountType(acct.data, 'EscrowV3')) {
543
+ const escrow = deserializeEscrowV3(acct.data);
544
+ }
545
+
546
+ // Get discriminator for filtering
547
+ const disc = getAccountDiscriminator('Attestation'); // 8-byte Buffer
548
+ // Use with getProgramAccounts memcmp filter
549
+ ```
68
550
 
69
- ## Program IDs (Mainnet)
551
+ ## Security
70
552
 
71
- | Program | Address |
72
- |---------|---------|
73
- | Identity | `BY4jzmnrui1K5gZ5z5xRQkVfEEMXYHYugtH1Ua867eyr` |
74
- | Reputation | `TQ4P9R2Y5FRyw1TZfwoWQ2Mf6XeohbGdhYNcDxh6YYh` |
75
- | Validation | `AdDWFa9oEmZdrTrhu8YTWu4ozbTP7e6qa9rvyqfAvM7N` |
76
- | Escrow | `STyY8w4ZHws3X1AMoocWuDYBoogVDwvymPy8Wifx5TH` |
553
+ - All transactions are returned **unsigned** — the SDK never holds private keys
554
+ - PDA derivation is deterministic and verified against on-chain seeds
555
+ - CPI boundaries enforce program-level authorization
556
+ - Escrow funds are held by PDA-owned accounts (no custodial risk)
77
557
 
78
- ## Notes
558
+ ## License
79
559
 
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' })`
560
+ MIT brainAI 2026