
Company News
Socket Joins New OpenJS Program to Fund Node.js Security Work
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.
@brainai/satp-client
Advanced tools
SATP client SDK surface prepared for release-candidate review; publish only after the release packet passes.
@brainai/satp-clientSolana Agent Token Protocol — JavaScript/TypeScript SDK for interacting with the SATP V3 devnet programs.
Version: 3.3.0 | Tests: 101 unit + 16 devnet integration | Programs: 6
npm install git+https://github.com/brainAI-bot/satp.git#<SATP_COMMIT>
The current review package is @brainai/satp-client@0.0.0-extraction and
remains unpublished. Pin a reviewed commit for consumers. Do not publish to npm
until the release packet passes.
Mainnet program IDs are intentionally not enabled in this release candidate.
Constructors and helpers fail closed for network: 'mainnet' until an approved
mainnet decision packet provides production program IDs.
Runtime dependency: @solana/web3.js ^1.98.4
const { SATPV3SDK } = require('@brainai/satp-client');
// Initialize (devnet by default)
const sdk = new SATPV3SDK({ network: 'devnet' });
// Check if an agent has an identity
const exists = await sdk.hasIdentity('brainChain');
console.log(exists); // true
// Read a Genesis Record
const record = await sdk.getGenesisRecord('brainChain');
console.log(record.agentName, record.category, record.isActive);
// Build a transaction (unsigned — sign with your wallet)
const tx = await sdk.buildCreateIdentity(creatorPubkey, 'myAgent', {
agentName: 'My Agent',
description: 'An AI agent on Solana',
category: 'assistant',
capabilities: ['chat', 'code'],
metadataUri: 'https://example.com/meta.json',
});
// Sign and send tx with your wallet...
┌─────────────────────────────────────────────────────────────────┐
│ SATP V3 SDK │
├─────────────┬──────────────┬──────────────┬─────────────────────┤
│ Identity │ Reviews │ Attestations │ Escrow │
│ (20 methods)│ (7 methods) │ (3 methods) │ (10 methods) │
├─────────────┼──────────────┼──────────────┤ │
│ Reputation │ Validation │ Migration │ │
│ (1 method) │ (1 method) │ (1 method) │ │
├─────────────┴──────────────┴──────────────┴─────────────────────┤
│ PDA Derivation │ Borsh Serialization │ RPC Helpers │
└─────────────────┴───────────────────────┴───────────────────────┘
| Program | Devnet | Description |
|---|---|---|
identity_v3 | GTppU4E44BqXTQgbqMZ68ozFzhP1TLty3EGnzzjtNZfG | Agent identity, names, wallets, face/birth |
reviews_v3 | r9XX4frcqxxAZ6Au9V5PA3EAxs1zoNckqLLmoSRcNr4 | Peer reviews with 1-5 star ratings |
attestations_v3 | 6Xd1dAQJPvQRJ4Ntr6LtPTjDjPUZ8nfnmYLZaZ2DtrdD | Third-party attestations & proofs |
reputation_v3 | 2Lz7KzMvKdrGeAuS8WPHu7jK2yScrnKVgacpYVEuDjkJ | Weighted reputation scoring (CPI → identity) |
validation_v3 | 6rYRiCYidJYV7QvKrzKGgNu4oMh6BAvynked69R7xMbV | Validation level computation (CPI → identity) |
escrow_v3 | HXCUWKR2NvRcZ7rNAJHwPcH6QAAWaLR4bRFbfyuDND6C | SOL escrow for agent jobs |
buildSatpTrustPacket(opts) creates a deterministic, offline trust packet for
consumer preflight and release-packet review. It uses the same inputs as
prepareIdentityAttestationRequest, then includes the derived program IDs,
Genesis PDA, attestation PDA, request hash, and the unsigned request object.
The packet is intentionally read-only: flags.signingRequired,
flags.transactionRequired, flags.writesRequired, and
flags.livePaymentRequired are all false; instructions and signers
are empty; and transaction is null.
const {
buildSatpTrustPacket,
validateSatpTrustPacket,
} = require('@brainai/satp-client');
const trustPacket = buildSatpTrustPacket({
subjectWallet: '11111111111111111111111111111111',
agentId: 'brainChain',
claimType: 'identity',
metadataHash: '93d122f8879fe87c186c10a00db8fbc80a73cecd2ede44b9ffa6410be3c2b805',
network: 'devnet',
});
const validation = validateSatpTrustPacket(trustPacket);
if (!validation.ok) throw new Error(validation.errors.join('; '));
validateSatpTrustPacket(packet) returns { ok, errors }. Validation requires
packetType: 'satp-trust-packet' and
mode: 'offline-readonly-trust-packet', rejects changed read-only flags, and
re-derives the expected packet so tampered PDA, program, request, or hash fields
surface as explicit errors.
const sdk = new SATPV3SDK({ network, rpcUrl });
// network: 'devnet' (default). 'mainnet' fails closed until approved IDs exist.
// rpcUrl: optional custom RPC endpoint
| Method | Description |
|---|---|
buildCreateIdentity(creator, agentId, meta) | Create a new agent identity (Genesis Record) |
buildBurnToBecome(authority, agentId, faceImage, faceMint, faceBurnTx) | Burn NFT to set agent's face (birth ritual) |
buildUpdateIdentity(authority, agentId, updates) | Update mutable fields (description, capabilities, metadata) |
buildProposeAuthority(authority, agentId, newAuthority) | Propose authority transfer (2-step) |
buildAcceptAuthority(newAuthority, agentId) | Accept proposed authority transfer |
buildCancelAuthorityTransfer(authority, agentId) | Cancel pending authority transfer |
buildRegisterName(authority, agentId, name) | Register a unique name for an agent |
buildReleaseName(authority, agentId, name) | Release a registered name |
buildLinkWallet(authority, agentId, wallet, chain, label) | Link an external wallet to identity |
buildUnlinkWallet(authority, agentId, wallet) | Unlink an external wallet |
buildInitMintTracker(authority, agentId) | Initialize NFT mint tracker |
buildRecordMint(authority, agentId) | Record an NFT mint event |
buildDeactivateIdentity(authority, agentId) | Deactivate an identity |
buildReactivateIdentity(authority, agentId) | Reactivate a deactivated identity |
getGenesisRecord(agentId) | Read a Genesis Record from chain |
hasIdentity(agentId) | Check if an agent has an identity |
getEscrowPDA(client, description, nonce) | Derive escrow PDA (sync) |
buildMigrateV2ToV3(v2Authority, agentId, meta) | Migrate from V2 to V3 identity |
const record = await sdk.getGenesisRecord('brainChain');
// Returns:
{
agentIdHash: string, // SHA-256 of agent_id
agentName: string, // Display name
description: string, // Agent description
category: string, // e.g. "developer", "assistant"
capabilities: string[], // e.g. ["solana", "code"]
metadataUri: string, // Off-chain metadata URL
faceImage: string, // Face image URL (after birth)
faceMint: string, // NFT mint address (after birth)
faceBurnTx: string, // Burn transaction signature
genesisRecord: number, // Unix timestamp of birth
isBorn: boolean, // Whether agent has completed birth ritual
isActive: boolean, // Whether identity is active
authority: string, // Current authority pubkey
pendingAuthority: string | null,
reputationScore: number, // CPI-updated reputation
validationLevel: number, // CPI-updated validation
createdAt: number, // Unix timestamp
updatedAt: number, // Unix timestamp
}
| Method | Description |
|---|---|
buildInitReviewCounter(payer, agentId) | Initialize review counter for an agent |
buildCreateReview(reviewer, agentId, rating, text, metadata, opts) | Create a 1-5 star review |
buildCreateReviewWithSelfCheck(reviewer, agentId, rating, text, metadata) | Create review with self-review prevention |
buildUpdateReview(reviewer, reviewPDA, updates) | Update an existing review |
buildDeleteReview(reviewer, reviewPDA) | Soft-delete a review |
getReview(agentId, reviewer) | Read a review from chain |
getReviewCount(agentId) | Get total review count for an agent |
// Create a review
const tx = await sdk.buildCreateReview(
reviewerPubkey,
'brainChain', // agent being reviewed
5, // rating (1-5)
'Excellent Solana dev',
'metadata',
{ category: 'development' }
);
| Method | Description |
|---|---|
buildCreateAttestation(issuer, agentId, type, proofData, expiresAt) | Issue an attestation |
buildVerifyAttestation(issuer, attestationPDA) | Mark attestation as verified |
buildRevokeAttestation(issuer, attestationPDA) | Revoke an attestation |
// Issue a KYC attestation
const tx = await sdk.buildCreateAttestation(
issuerPubkey,
'brainChain',
'kyc', // attestation type
'proof-hash-here',
Math.floor(Date.now()/1000) + 86400 * 365 // expires in 1 year
);
| Method | Description |
|---|---|
buildRecomputeReputation(caller, agentId, reviewAccounts) | Recompute reputation score from reviews (CPI → identity) |
buildRecomputeLevel(caller, agentId, attestationAccounts) | Recompute validation level from attestations (CPI → identity) |
These use Cross-Program Invocation to update fields directly on the Genesis Record.
Full escrow lifecycle for agent marketplace jobs.
| Method | Description |
|---|---|
buildCreateEscrow(client, agentWallet, agentId, amount, description, deadline, nonce, opts) | Create SOL escrow for a job |
buildSubmitWork(agent, escrowPDA, workProof) | Agent submits work proof |
buildEscrowRelease(client, agent, escrowPDA) | Client releases full payment |
buildPartialRelease(client, agent, escrowPDA, amount) | Client releases partial payment |
buildCancelEscrow(client, escrowPDA) | Cancel escrow (refund client) |
buildRaiseDispute(signer, escrowPDA, reason) | Raise a dispute |
buildResolveDispute(arbiter, agent, client, escrowPDA, agentAmt, clientAmt) | Arbiter resolves dispute |
buildExtendDeadline(client, escrowPDA, newDeadline) | Extend job deadline |
buildCloseEscrow(client, escrowPDA) | Close completed/cancelled escrow (reclaim rent) |
getEscrow(escrowPDA) | Read escrow state from chain |
Created → WorkSubmitted → Released (full or partial)
↓ ↓ ↓
Cancelled Disputed Closed (rent reclaimed)
↓
Resolved (split)
↓
Closed
// Create an escrow (0.5 SOL for a coding job)
const tx = await sdk.buildCreateEscrow(
clientPubkey,
agentWallet,
'brainChain',
0.5 * 1e9, // lamports
'Build SATP integration',
Math.floor(Date.now()/1000) + 86400 * 7, // 7 day deadline
0, // nonce (for multiple escrows with same description)
{ arbiter: arbiterPubkey }
);
v3-pda.js)const {
hashAgentId, // SHA-256 hash of agent_id string
hashName, // SHA-256 hash of name string
getGenesisPDA, // [b"genesis_record", agent_id_hash]
getNameRegistryPDA, // [b"name_registry_v3", name_hash]
getLinkedWalletPDA, // [b"linked_wallet_v3", agent_id_hash, wallet]
getV3MintTrackerPDA, // [b"mint_tracker_v3", agent_id_hash]
getV3ReviewPDA, // [b"review_v3", agent_id_hash, reviewer]
getV3ReviewCounterPDA, // [b"review_counter_v3", agent_id_hash]
getV3AttestationPDA, // [b"attestation_v3", agent_id_hash, issuer, type_hash]
getV3ReputationAuthorityPDA, // [b"reputation_authority", agent_id_hash]
getV3ValidationAuthorityPDA, // [b"validation_authority", agent_id_hash]
getV3EscrowPDA, // [b"escrow_v3", client, desc_hash, nonce_le]
getV3ProgramIds, // Returns all 6 program IDs for network
} = require('@brainai/satp-client/src/v3-pda');
v3-sdk.js)const {
deriveEscrowPda, // Derive escrow PDA from params
descriptionHash, // SHA-256 hash of description string
EscrowStatus, // Enum: { Active: 0, WorkSubmitted: 1, Released: 2, Cancelled: 3, Disputed: 4, Resolved: 5 }
escrowStatusLabel, // Convert status number to human-readable string
escrowRemaining, // Calculate remaining escrow balance
isEscrowExpired, // Check if escrow has passed deadline
} = require('@brainai/satp-client/src/v3-sdk');
All build* methods return an unsigned Transaction object. Your application is responsible for:
recentBlockhash and feePayerconst tx = await sdk.buildCreateIdentity(wallet.publicKey, 'myAgent', { ... });
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
tx.feePayer = wallet.publicKey;
tx.sign(wallet);
const sig = await connection.sendRawTransaction(tx.serialize());
await connection.confirmTransaction(sig);
The SATP V3 API is available at https://agentfolio.bot/api/v3/:
| Endpoint | Description |
|---|---|
GET /api/v3/health | API health + program IDs |
GET /api/v3/escrow/by-client/:wallet | Escrows by client wallet |
GET /api/v3/escrow/by-agent/:wallet | Escrows by agent wallet |
GET /api/v3/escrow/by-agent-id/:agentId | Escrows by SATP agent_id |
| + 18 more | See OpenAPI spec in docs/ |
# Unit tests (101)
node test-v3.js
# Devnet integration tests (16)
node test-v3-devnet.js
# CPI integration tests (35)
cd .. && node tests/devnet-cpi-integration.js
# Release-safety defaults and mainnet fail-closed checks
node test-release-safety.js
// Devnet (default)
const sdk = new SATPV3SDK();
// Explicit devnet
const sdk = new SATPV3SDK({ network: 'devnet' });
// Custom RPC
const sdk = new SATPV3SDK({ rpcUrl: 'https://my-rpc.example.com' });
// Mainnet currently fails closed until approved program IDs are configured
assert.throws(() => new SATPV3SDK({ network: 'mainnet' }));
Zero-dependency Borsh deserialization for all 8 SATP V3 account types. Decode raw on-chain data without the borsh library.
| Account | Program | Deserializer |
|---|---|---|
| GenesisRecord | Identity V3 | deserializeGenesisRecord(data) |
| LinkedWallet | Identity V3 | deserializeLinkedWallet(data) |
| MintTracker | Identity V3 | deserializeMintTracker(data) |
| NameRegistry | Identity V3 | deserializeNameRegistry(data) |
| Review | Reviews V3 | deserializeReview(data) |
| ReviewCounter | Reviews V3 | deserializeReviewCounter(data) |
| Attestation | Attestations V3 | deserializeAttestation(data) |
| EscrowV3 | Escrow V3 | deserializeEscrowV3(data) |
const { deserializeGenesisRecord, deserializeAttestation } = require('@brainai/satp-client');
const { Connection, PublicKey } = require('@solana/web3.js');
const conn = new Connection('https://api.devnet.solana.com');
// Fetch raw account and deserialize
const acct = await conn.getAccountInfo(new PublicKey('...'));
const genesis = deserializeGenesisRecord(acct.data);
console.log(genesis.agentName, genesis.reputationScore, genesis.isBorn);
const { deserializeAccount } = require('@brainai/satp-client');
// Automatically detects type from 8-byte Anchor discriminator
const { type, data } = deserializeAccount(acct.data);
console.log(type); // "GenesisRecord" | "Attestation" | "EscrowV3" | ...
console.log(data); // Fully parsed object
const { deserializeBatch, DISCRIMINATORS } = require('@brainai/satp-client');
const accounts = await conn.getProgramAccounts(REVIEWS_PROGRAM_ID);
const reviews = deserializeBatch(accounts, 'Review');
// [{ pubkey: "...", type: "Review", data: { agentId, rating, ... } }, ...]
const { BorshReader } = require('@brainai/satp-client');
// Low-level reader for custom account layouts
const r = new BorshReader(acct.data);
r.skipDiscriminator(); // skip 8-byte Anchor discriminator
const hash = r.readFixedBytes32(); // [u8; 32]
const name = r.readString(); // Borsh String
const items = r.readVecString(); // Vec<String>
const pk = r.readPubkeyBase58(); // Pubkey → base58
const opt = r.readOptionI64(); // Option<i64> → number | null
const { isAccountType, getAccountDiscriminator, DISCRIMINATORS } = require('@brainai/satp-client');
// Check account type before deserializing
if (isAccountType(acct.data, 'EscrowV3')) {
const escrow = deserializeEscrowV3(acct.data);
}
// Get discriminator for filtering
const disc = getAccountDiscriminator('Attestation'); // 8-byte Buffer
// Use with getProgramAccounts memcmp filter
MIT — brainAI 2026
FAQs
SATP client SDK for reviewed Solana Agent Trust Protocol integrations.
The npm package @brainai/satp-client receives a total of 14 weekly downloads. As such, @brainai/satp-client popularity was classified as not popular.
We found that @brainai/satp-client demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Company News
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.

Security News
Two compromised GitHub Actions were re-enabled with malicious tags intact, exposing thousands of downstream repositories to Mini Shai-Hulud.

Research
/Security News
A malicious Firefox extension fetches its payload after installation to evade detection, steal Google session cookies, and automate account takeover.