Requirements
- Target platform
- OpenClaw
- Install method
- Manual import
- Extraction
- Extract archive
- Prerequisites
- OpenClaw
- Primary doc
- SKILL.md
TypeScript SDK for the 8004 Trustless Agent Registry on Solana. Covers agent registration, feedback/SEAL v1, ATOM reputation engine, signing, indexer queries...
TypeScript SDK for the 8004 Trustless Agent Registry on Solana. Covers agent registration, feedback/SEAL v1, ATOM reputation engine, signing, indexer queries...
Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.
I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete.
I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run.
You are an AI agent with access to the 8004-solana TypeScript SDK. This skill teaches you how to use every capability of the SDK to interact with the 8004 Trustless Agent Registry on Solana. Version note (SDK 0.6.x): Single-collection architecture is active. createCollection() and updateCollectionUri() are deprecated and return { success: false, error }. Feedback reads (readAllFeedback, getClients, getLastIndex, readFeedback, etc.) rely on the indexer.
npm install 8004-solana @solana/web3.js
import { // Core SDK SolanaSDK, IPFSClient, // Builders buildRegistrationFileJson, // Enums & Types ServiceType, // MCP, A2A, ENS, DID, WALLET, OASF TrustTier, // Unrated=0, Bronze=1, Silver=2, Gold=3, Platinum=4 Tag, // Standardized tag constants // ATOM Engine AtomStats, trustTierToString, // SEAL v1 computeSealHash, computeFeedbackLeafV1, verifySealHash, createSealParams, validateSealInputs, MAX_TAG_LEN, // 32 bytes MAX_ENDPOINT_LEN, // 250 bytes MAX_URI_LEN, // 250 bytes // OASF Taxonomy getAllSkills, getAllDomains, // Tag helpers isKnownTag, getTagDescription, // Signing buildSignedPayload, verifySignedPayload, parseSignedPayload, normalizeSignData, createNonce, canonicalizeJson, // Value encoding encodeReputationValue, decodeToDecimalString, decodeToNumber, // Crypto utilities keccak256, sha256, sha256Sync, // Node.js only // Hash-chain replay replayFeedbackChain, replayResponseChain, replayRevokeChain, // Indexer IndexerClient, // Endpoint crawler EndpointCrawler, // Error classes IndexerError, IndexerUnavailableError, IndexerTimeoutError, IndexerRateLimitError, UnsupportedRpcError, RpcNetworkError, } from '8004-solana'; import { Keypair, PublicKey } from '@solana/web3.js';
const sdk = new SolanaSDK({ cluster: 'devnet' });
const signer = Keypair.fromSecretKey( Uint8Array.from(JSON.parse(process.env.SOLANA_PRIVATE_KEY!)) ); const sdk = new SolanaSDK({ signer });
const sdk = new SolanaSDK({ rpcUrl: 'https://your-helius-rpc.helius.dev', signer, });
const sdk = new SolanaSDK({ cluster: 'devnet', rpcUrl: 'https://...', signer: keypair, indexerUrl: 'https://xxx.supabase.co/rest/v1', indexerApiKey: process.env.INDEXER_API_KEY, // if your indexer requires an API key, keep it in env useIndexer: true, indexerFallback: true, forceOnChain: false, });
// Pinata (recommended) const ipfsPinata = new IPFSClient({ pinataEnabled: true, pinataJwt: process.env.PINATA_JWT!, }); // Local node const ipfsLocal = new IPFSClient({ url: 'http://localhost:5001' });
const metadata = buildRegistrationFileJson({ name: 'My Agent', description: 'Autonomous trading agent', image: 'ipfs://QmImageCid...', services: [ { type: ServiceType.MCP, value: 'https://my-agent.com/mcp' }, { type: ServiceType.A2A, value: 'https://my-agent.com/a2a' }, ], skills: ['advanced_reasoning_planning/strategic_planning'], domains: ['finance_and_business/finance'], x402Support: true, });
const cid = await ipfs.addJson(metadata);
const result = await sdk.registerAgent(`ipfs://${cid}`); // result.asset -> PublicKey (agent NFT address) // result.signature -> transaction signature // ATOM stats are auto-initialized
const opWallet = Keypair.generate(); await sdk.setAgentWallet(result.asset, opWallet);
All agents register into the base collection automatically. createCollection() and updateCollectionUri() are deprecated and return { success: false }. const baseCollection = await sdk.getBaseCollection();
// Load agent const agent = await sdk.loadAgent(assetPubkey); // agent.getOwnerPublicKey(), agent.getAgentWalletPublicKey(), agent.agent_uri, etc. // Check existence const exists = await sdk.agentExists(assetPubkey); // Get owner const owner = await sdk.getAgentOwner(assetPubkey); // Check ownership const isMine = await sdk.isAgentOwner(assetPubkey, myPubkey); // On-chain metadata const version = await sdk.getMetadata(assetPubkey, 'version');
const allAgents = await sdk.getAllAgents(); const withFeedbacks = await sdk.getAllAgents({ includeFeedbacks: true }); const myAgents = await sdk.getAgentsByOwner(ownerPubkey);
// Update metadata URI await sdk.setAgentUri(assetPubkey, collectionPubkey, `ipfs://${newCid}`); // Set on-chain key-value metadata await sdk.setMetadata(assetPubkey, 'version', '2.0.0'); // First call: ~0.00319 SOL (PDA rent). Updates: ~0.000005 SOL (tx fee only) // Immutable metadata (permanent, cannot change or delete) await sdk.setMetadata(assetPubkey, 'certification', 'audited-2026', true); // Delete metadata (recovers rent) await sdk.deleteMetadata(assetPubkey, 'version'); // Transfer ownership await sdk.transferAgent(assetPubkey, collectionPubkey, newOwnerPubkey); // Sync owner after external NFT transfer await sdk.syncOwner(assetPubkey);
// Decimal string auto-encodes: "99.77" -> { value: 9977n, valueDecimals: 2 } await sdk.giveFeedback(assetPubkey, { value: '99.77', tag1: Tag.uptime, tag2: Tag.day, score: 95, // 0-100, optional endpoint: '/api/v1/generate', // optional, max 250 bytes feedbackUri: `ipfs://${feedbackCid}`, feedbackFileHash, // optional, 32 bytes Buffer (links file to SEAL) });
FieldTypeRequiredDescriptionvaluestring | number | bigintYesMetric value. Strings auto-encode decimals ("99.77" -> 9977n, 2)valueDecimalsnumber (0-6)NoOnly needed for raw int/bigint. Auto-detected for stringsscorenumber (0-100)NoExplicit ATOM score. If omitted, inferred from tag1tag1stringNoCategory tag (max 32 UTF-8 bytes)tag2stringNoPeriod/network tag (max 32 UTF-8 bytes)endpointstringNoEndpoint used (max 250 UTF-8 bytes)feedbackUristringYesURI to detailed feedback file (IPFS/HTTPS, max 250 bytes)feedbackFileHashBufferNoSHA-256 of feedback file content (32 bytes). Binds file to on-chain SEAL
// Percentage with 2 decimals: 99.75% const feedbackExamples = [ { value: '99.75', tag1: Tag.uptime }, // -> encoded: value=9975n, valueDecimals=2 // Milliseconds: 250ms { value: 250, tag1: Tag.responseTime, valueDecimals: 0 }, // Currency: $150.25 { value: '150.25', tag1: Tag.revenues, tag2: Tag.week }, // Negative PnL: -$15.5 { value: '-15.5', tag1: Tag.tradingYield, tag2: Tag.month }, // Binary check: reachable { value: 1, tag1: Tag.reachable, valueDecimals: 0, score: 100 }, // Quality rating (score only) { value: '85', tag1: Tag.starred, score: 85 }, ];
score: 95 -> explicit quality score, used directly by ATOM score: undefined/null -> ATOM infers from tag1 if it's a known tag (uptime, successRate, starred) Tags without auto-score (responseTime, revenues, etc.) require explicit score for ATOM impact ATOM-enabled tags (auto-score from value): starred, uptime, successRate Context-dependent tags (require explicit score): reachable, ownerVerified, responseTime, blocktimeFreshness, revenues, tradingYield
// Single feedback const fb = await sdk.readFeedback(assetPubkey, clientPubkey, 0); // fb.value, fb.valueDecimals, fb.score, fb.tag1, fb.tag2, fb.sealHash // All feedbacks for agent (indexer-backed) const all = await sdk.readAllFeedback(assetPubkey); const withRevoked = await sdk.readAllFeedback(assetPubkey, true); // Last feedback index for a specific client (NOT a count) const lastIndex = await sdk.getLastIndex(assetPubkey, clientPubkey); const nextIndex = lastIndex + 1n; // if no feedback yet: lastIndex = -1n, nextIndex = 0n // All clients who gave feedback (indexer-backed) const clients = await sdk.getClients(assetPubkey); // Via indexer (faster, no premium RPC needed) const feedbacks = await sdk.getFeedbacksFromIndexer(assetPubkey, { limit: 50 }); const byEndpoint = await sdk.getFeedbacksByEndpoint('/api/generate'); const byTag = await sdk.getFeedbacksByTag('uptime');
// Requires the sealHash from the original feedback const fb = await sdk.readFeedback(assetPubkey, clientPubkey, 0); await sdk.revokeFeedback(assetPubkey, 0, fb.sealHash!);
await sdk.appendResponse( assetPubkey, clientPubkey, 0, // feedbackIndex fb.sealHash!, // sealHash from the feedback `ipfs://${responseCid}`, // response URI ); // Read responses const responses = await sdk.readResponses(assetPubkey, clientPubkey, 0); const count = await sdk.getResponseCount(assetPubkey, clientPubkey, 0);
const summary = await sdk.getSummary(assetPubkey); // summary.averageScore -> 0-100 // summary.totalFeedbacks // summary.positiveCount -> score >= 50 // summary.negativeCount -> score < 50 // With filters const filtered = await sdk.getSummary(assetPubkey, 70); // minScore=70 const byClient = await sdk.getSummary(assetPubkey, undefined, clientPubkey);
const atom = await sdk.getAtomStats(assetPubkey); if (atom) { atom.quality_score; // 0-10000 (divide by 100 for percentage) atom.confidence; // 0-10000 atom.ema_score_fast; // Fast EMA (reacts quickly) atom.ema_score_slow; // Slow EMA (stable baseline) atom.ema_volatility; // Score instability atom.diversity_ratio; // 0-255 (unique caller diversity) atom.risk_score; // 0-100 atom.trust_tier; // 0-4 // Helper methods atom.getQualityPercent(); // quality_score / 100 atom.getConfidencePercent(); // confidence / 100 atom.getAverageScore(); // ema_score_slow / 100 atom.estimateUniqueClients(); // HyperLogLog estimation atom.getTrustTier(); // TrustTier enum }
const tier = await sdk.getTrustTier(assetPubkey); // TrustTier.Unrated = 0 // TrustTier.Bronze = 1 // TrustTier.Silver = 2 // TrustTier.Gold = 3 // TrustTier.Platinum = 4 const name = trustTierToString(tier); // "Gold"
const enriched = await sdk.getEnrichedSummary(assetPubkey); if (enriched) { enriched.trustTier; enriched.qualityScore; // 0-10000 enriched.confidence; // 0-10000 enriched.riskScore; // 0-100 enriched.diversityRatio; // 0-255 enriched.uniqueCallers; // HLL estimate enriched.emaScoreFast; enriched.emaScoreSlow; enriched.volatility; enriched.totalFeedbacks; enriched.averageScore; // 0-100 enriched.positiveCount; enriched.negativeCount; }
const rep = await sdk.getAgentReputationFromIndexer(assetPubkey);
const signedJson = sdk.sign(assetPubkey, { action: 'authorize', target: 'task-123', timestamp: Date.now(), }); // Returns: JSON string of SignedPayloadV1
// From JSON string const isValidFromJson = await sdk.verify(signedJson, assetPubkey); // From IPFS URI const isValidFromIpfs = await sdk.verify('ipfs://QmPayload...', assetPubkey); // From HTTPS URL const isValidFromHttps = await sdk.verify('https://example.com/signed.json', assetPubkey); // From file path const isValidFromFile = await sdk.verify('./signed-payload.json', assetPubkey); // With explicit public key const isValidWithPubkey = await sdk.verify(signedJson, assetPubkey, walletPubkey);
const exampleSignedPayload = { v: 1, alg: 'ed25519', asset: 'base58...', // agent asset pubkey nonce: 'random-base58', issuedAt: 1234567890, // unix seconds data: { action: 'authorize', target: 'task-123' }, // your payload sig: 'base58...', // Ed25519 signature };
const defaultReport = await sdk.isItAlive(assetPubkey); // report.status: 'live' | 'partially' | 'not_live' // report.okCount, report.totalPinged, report.skippedCount // report.liveServices[], report.deadServices[], report.skippedServices[] // With options const tunedReport = await sdk.isItAlive(assetPubkey, { timeoutMs: 10000, concurrency: 2, treatAuthAsAlive: true, // 401/403 = alive includeTypes: [ServiceType.MCP], // only check MCP endpoints });
SEAL provides client-side hash computation matching on-chain Keccak256. Required for revokeFeedback() and appendResponse(). // Build params (with optional feedbackFileHash) const fileHash = await SolanaSDK.computeHash(JSON.stringify(feedbackFile)); const params = createSealParams( 9977n, // value (i64) 2, // decimals 85, // score (or null) 'uptime', // tag1 'day', // tag2 'https://api.example.com', // endpoint (or null) 'ipfs://QmFeedback...', // feedbackUri fileHash, // feedbackFileHash (or null) ); // Validate inputs before hashing (throws on invalid params) validateSealInputs(params); // Compute hash const sealHash = computeSealHash(params); // Buffer, 32 bytes (Keccak256) // Verify const valid = verifySealHash({ ...params, sealHash }); // true // Compute feedback leaf (for hash-chain verification) const leaf = computeFeedbackLeafV1( assetPubkey.toBuffer(), clientPubkey.toBuffer(), 0n, // feedbackIndex sealHash, 12345n, // slot );
FieldMax bytesConstanttag1, tag232 UTF-8MAX_TAG_LENendpoint250 UTF-8MAX_ENDPOINT_LENfeedbackUri250 UTF-8MAX_URI_LENfeedbackFileHash32 exact-
const integrity = await sdk.verifyIntegrity(assetPubkey); // integrity.valid -> boolean // integrity.status -> 'valid' | 'syncing' | 'corrupted' | 'error' // integrity.trustworthy -> boolean // integrity.totalLag -> bigint (blocks behind) // integrity.chains.feedback, .response, .revoke
const deep = await sdk.verifyIntegrityDeep(assetPubkey, { spotChecks: 10, checkBoundaries: true, verifyContent: false, // true = also verify IPFS content hashes (slow) }); // deep.spotChecksPassed, deep.missingItems, deep.modifiedItems
const full = await sdk.verifyIntegrityFull(assetPubkey, { onProgress: (chain, count, total) => { console.log(`${chain}: ${count}/${total}`); }, });
const results = await sdk.searchAgents({ owner: 'base58...', collection: 'base58...', wallet: 'base58...', limit: 20, offset: 0, });
const top = await sdk.getLeaderboard({ minTier: 2, // Silver+ limit: 50, collection: 'base58...', });
const global = await sdk.getGlobalStats(); // global.total_agents, total_feedbacks, platinum_agents, gold_agents, avg_quality
const agent = await sdk.getAgentByWallet(walletPubkey.toBase58());
const crawler = new EndpointCrawler(5000); const mcp = await crawler.fetchMcpCapabilities('https://agent.com/mcp'); // mcp.mcpTools, mcp.mcpPrompts, mcp.mcpResources const a2a = await crawler.fetchA2aCapabilities('https://agent.com'); // a2a.a2aSkills
// Chain identity (CAIP-2 format) const chain = await sdk.chainId(); // 'solana-devnet' const cluster = sdk.getCluster(); // 'devnet' | 'mainnet-beta' | 'testnet' // Program IDs for all registries const programs = sdk.getProgramIds(); // programs.identityRegistry -> PublicKey // programs.reputationRegistry -> PublicKey // programs.validationRegistry -> PublicKey // Registry addresses as strings (parity with agent0-ts) const regs = sdk.registries(); // { IDENTITY: 'base58...', REPUTATION: 'base58...', VALIDATION: 'base58...' } // RPC info const rpcUrl = sdk.getRpcUrl(); const isDefaultRpc = sdk.isUsingDefaultDevnetRpc(); const canBulkQuery = sdk.supportsAdvancedQueries(); const readOnly = sdk.isReadOnly; // Base collection (single-collection architecture in v0.6.x) const base = await sdk.getBaseCollection(); // Advanced: access underlying clients const solanaClient = sdk.getSolanaClient(); const feedbackMgr = sdk.getFeedbackManager();
ConstantStringValue TypeATOM Auto-ScoreTag.starred'starred'0-100YesTag.uptime'uptime'percentageYesTag.successRate'successRate'percentageYesTag.reachable'reachable'0 or 1NoTag.ownerVerified'ownerVerified'0 or 1NoTag.responseTime'responseTime'msNoTag.blocktimeFreshness'blocktimeFreshness'blocksNoTag.revenues'revenues'currencyNoTag.tradingYield'tradingYield'percentageNo
ConstantStringTag.day'day'Tag.week'week'Tag.month'month'Tag.year'year'
ConstantStringTag.x402ResourceDelivered'x402-resource-delivered'Tag.x402DeliveryFailed'x402-delivery-failed'Tag.x402DeliveryTimeout'x402-delivery-timeout'Tag.x402QualityIssue'x402-quality-issue'
ConstantStringTag.x402GoodPayer'x402-good-payer'Tag.x402PaymentFailed'x402-payment-failed'Tag.x402InsufficientFunds'x402-insufficient-funds'Tag.x402InvalidSignature'x402-invalid-signature'
ConstantStringTag.x402Evm'exact-evm'Tag.x402Svm'exact-svm'
isKnownTag('uptime'); // true isKnownTag('custom-metric'); // false getTagDescription('successRate'); // 'Task completion success percentage' Custom tags are fully supported - any string up to 32 UTF-8 bytes.
// List taxonomy slugs const skills = getAllSkills(); // 136 skills const domains = getAllDomains(); // 204 domains
// SHA-256 (async, browser-compatible via WebCrypto) const hash = await SolanaSDK.computeHash('My feedback content'); const bufHash = await SolanaSDK.computeHash(Buffer.from(jsonData)); // Returns: Buffer (32 bytes) // URI hash (zeros for IPFS/Arweave since CID is already content-addressable) const uriHash = await SolanaSDK.computeUriHash('https://example.com/data.json'); // -> SHA-256 of the URI string const ipfsHash = await SolanaSDK.computeUriHash('ipfs://Qm...'); // -> Buffer.alloc(32) (zeros) // Keccak-256 (synchronous, used by SEAL v1) import { keccak256 } from '8004-solana'; const k = keccak256(Buffer.from('data')); // SHA-256 sync (CJS context only β uses require('crypto'), throws in pure ESM or browser) import { sha256Sync } from '8004-solana'; const s = sha256Sync('data'); // Uint8Array (32 bytes)
import { encodeReputationValue, decodeToDecimalString, decodeToNumber, } from '8004-solana'; // Encode: decimal string -> { value: bigint, valueDecimals: number } const encoded = encodeReputationValue('99.77'); // { value: 9977n, valueDecimals: 2, normalized: '99.77' } const neg = encodeReputationValue('-15.5'); // { value: -155n, valueDecimals: 1, normalized: '-15.5' } const raw = encodeReputationValue(9977n, 2); // { value: 9977n, valueDecimals: 2, normalized: '99.77' } // Decode: bigint + decimals -> string or number decodeToDecimalString(9977n, 2); // '99.77' decodeToDecimalString(-155n, 1); // '-15.5' decodeToNumber(9977n, 2); // 99.77 // Limits: max 6 decimal places, clamped to i64 range
import { canonicalizeJson, normalizeSignData, createNonce, } from '8004-solana'; // RFC 8785 canonical JSON (deterministic key ordering, no whitespace) canonicalizeJson({ b: 2, a: 1 }); // '{"a":1,"b":2}' // Normalize data for signing (handles BigInt, PublicKey, Date, Buffer) const normalized = normalizeSignData({ amount: 100n, // -> { $bigint: '100' } key: somePubkey, // -> { $pubkey: 'base58...' } when: new Date(), // -> { $date: 'ISO...' } data: Buffer.from([1]), // -> { $bytes: 'AQ==', encoding: 'base64' } }); // Cryptographic nonce generation (base58-encoded random bytes) const nonce = createNonce(); // 16 bytes default const nonce32 = createNonce(32); // 32 bytes
// Add data const jsonCid = await ipfs.addJson({ key: 'value' }); const rawCid = await ipfs.add('raw string data'); const fileCid = await ipfs.addFile('./image.png'); // Add registration file (normalizes and formats) const registrationCid = await ipfs.addRegistrationFile(registrationFile); // Retrieve const data = await ipfs.get(jsonCid); // raw string const json = await ipfs.getJson(jsonCid); // parsed JSON const reg = await ipfs.getRegistrationFile(registrationCid); // RegistrationFile // Supports ipfs:// prefix const ipfsPrefixedData = await ipfs.get('ipfs://QmAbc...'); // Pin/unpin await ipfs.pin(fileCid); await ipfs.unpin(fileCid); // Cleanup await ipfs.close();
For browser wallets or external signing: // Get unsigned transaction const assetKeypair = Keypair.generate(); const prepared = await sdk.registerAgent(uri, undefined, { skipSend: true, signer: ownerPubkey, // required when SDK has no signer assetPubkey: assetKeypair.publicKey, // required in skipSend mode }); // prepared.transaction -> base64 serialized unsigned transaction // prepared.signer -> base58 of the required signer // For agent wallet (browser wallet flow) const { message, complete } = await sdk.prepareSetAgentWallet( assetPubkey, walletPubkey, { signer: ownerPubkey } // optional if SDK was initialized with signer ); const signature = await phantomWallet.signMessage(message); await complete(signature); All write methods accept { skipSend: true } in their options.
const indexer = sdk.getIndexerClient(); // Check availability const available = await sdk.isIndexerAvailable(); // Direct queries const agents = await indexer.getAgentsByOwner('base58...'); const feedbacks = await indexer.getFeedbacks('base58...', { limit: 100 }); const leaderboard = await indexer.getLeaderboard({ minTier: 3 });
await sdk.giveFeedback(assetPubkey, feedbackParams); // Poll until indexer catches up (returns true if synced, false on timeout) const synced = await sdk.waitForIndexerSync( async () => { const fbs = await sdk.getFeedbacksFromIndexer(assetPubkey); return fbs.length >= expectedCount; }, { timeout: 30000 } // ms, default 30s );
import { IndexerError, IndexerUnavailableError, IndexerTimeoutError, IndexerRateLimitError, UnsupportedRpcError, RpcNetworkError, } from '8004-solana'; try { const agents = await sdk.getAllAgents(); } catch (e) { if (e instanceof UnsupportedRpcError) { // Default RPC doesn't support getProgramAccounts // Use Helius, QuickNode, or Alchemy } if (e instanceof IndexerUnavailableError) { // Indexer is down, SDK falls back to RPC if indexerFallback=true } if (e instanceof IndexerRateLimitError) { // Back off and retry } }
getAllAgents(), getAgentsByOwner(), getCollectionAgents(), getCollections() Indexer-backed reads (readAllFeedback(), getClients(), getLastIndex(), readResponses()) do not require premium RPC, but they do require a reachable indexer.
OperationCostNotesregisterAgent()~0.00651 SOLIncludes ATOM auto-initgiveFeedback() (1st for agent)~0.00332 SOLCreates reputation PDAgiveFeedback() (subsequent)~0.00209 SOLFeedback PDA onlysetMetadata() (1st key)~0.00319 SOLPDA rentsetMetadata() (update)~0.000005 SOLTX fee onlyappendResponse() (1st)~0.00275 SOLResponse + index PDAsappendResponse() (subsequent)~0.00163 SOLResponse PDA onlyrevokeFeedback()~0.000005 SOLTX fee onlydeleteMetadata()recovers rentReturns lamports to owner
const report = await sdk.isItAlive(assetPubkey); if (report.status !== 'live') { await sdk.giveFeedback(assetPubkey, { value: 0, valueDecimals: 0, tag1: Tag.reachable, score: 0, feedbackUri: `ipfs://${alertCid}`, }); }
const uptimePercent = calculateUptime(); // your logic await sdk.giveFeedback(assetPubkey, { value: uptimePercent.toFixed(2), // "99.75" auto-encodes tag1: Tag.uptime, tag2: Tag.day, feedbackUri: `ipfs://${reportCid}`, });
const tier = await sdk.getTrustTier(assetPubkey); if (tier < TrustTier.Silver) { throw new Error('Agent trust too low for this operation'); }
// 1. Build the feedback file JSON (off-chain proof of payment) const feedbackFile = { version: '1.0', type: 'x402-feedback', agent: assetPubkey.toBase58(), client: clientPubkey.toBase58(), endpoint: '/api/generate', timestamp: new Date().toISOString(), proofOfPayment: { txHash: 'base58-tx-signature...', fromAddress: clientPubkey.toBase58(), toAddress: agentWalletPubkey.toBase58(), amount: '0.001', token: 'SOL', chainId: await sdk.chainId(), // 'solana-devnet' }, settlement: { success: true, network: 'solana', settledAt: new Date().toISOString(), }, result: { delivered: true, latencyMs: 230, quality: 'good', }, }; // 2. Upload to IPFS const feedbackCid = await ipfs.addJson(feedbackFile); // 3. Optionally compute content hash for SEAL integrity const feedbackFileHash = await SolanaSDK.computeHash( JSON.stringify(feedbackFile) ); // 4. Submit on-chain feedback with proof link await sdk.giveFeedback(assetPubkey, { value: '100.00', tag1: Tag.x402ResourceDelivered, tag2: Tag.x402Svm, score: 95, endpoint: '/api/generate', feedbackUri: `ipfs://${feedbackCid}`, feedbackFileHash, // links file content to on-chain SEAL }); // Agent-side: report good payer await sdk.giveFeedback(clientAgentPubkey, { value: '1', valueDecimals: 0, tag1: Tag.x402GoodPayer, tag2: Tag.x402Svm, score: 100, feedbackUri: `ipfs://${payerProofCid}`, });
const integrity = await sdk.verifyIntegrity(assetPubkey); if (!integrity.trustworthy) { console.warn(`Indexer data not trustworthy: ${integrity.status}`); // Fall back to on-chain queries }
import { PROGRAM_ID, // Agent Registry: 8oo48pya1SZD23ZhzoNMhxR2UGb8BRa41Su4qP9EuaWm MPL_CORE_PROGRAM_ID, // Metaplex Core: CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d ATOM_ENGINE_PROGRAM_ID, // ATOM: AToM1iKaniUCuWfHd5WQy5aLgJYWMiKq78NtNJmtzSXJ } from '8004-solana';
Agent frameworks, memory systems, reasoning layers, and model-native orchestration.
Largest current source with strong distribution and engagement signals.