{
  "schemaVersion": "1.0",
  "item": {
    "slug": "solana-agent-registry",
    "name": "Solana On-Chain Agent Registry, Reputation & Trust",
    "source": "tencent",
    "type": "skill",
    "category": "AI 智能",
    "sourceUrl": "https://clawhub.ai/MonteCrypto999/solana-agent-registry",
    "canonicalUrl": "https://clawhub.ai/MonteCrypto999/solana-agent-registry",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/solana-agent-registry",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=solana-agent-registry",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "skill.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "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."
        },
        {
          "label": "Upgrade existing",
          "body": "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."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-30T16:55:25.780Z",
      "expiresAt": "2026-05-07T16:55:25.780Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
        "contentDisposition": "attachment; filename=\"network-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/solana-agent-registry"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/solana-agent-registry",
    "agentPageUrl": "https://openagent3.xyz/skills/solana-agent-registry/agent",
    "manifestUrl": "https://openagent3.xyz/skills/solana-agent-registry/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/solana-agent-registry/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "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."
      },
      {
        "label": "Upgrade existing",
        "body": "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."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "8004-solana SDK Skill",
        "body": "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.\n\nVersion note (SDK 0.6.x):\n\nSingle-collection architecture is active. createCollection() and updateCollectionUri() are deprecated and return { success: false, error }.\nFeedback reads (readAllFeedback, getClients, getLastIndex, readFeedback, etc.) rely on the indexer."
      },
      {
        "title": "Install",
        "body": "npm install 8004-solana @solana/web3.js"
      },
      {
        "title": "Imports",
        "body": "import {\n  // Core SDK\n  SolanaSDK,\n  IPFSClient,\n\n  // Builders\n  buildRegistrationFileJson,\n\n  // Enums & Types\n  ServiceType,       // MCP, A2A, ENS, DID, WALLET, OASF\n  TrustTier,         // Unrated=0, Bronze=1, Silver=2, Gold=3, Platinum=4\n  Tag,               // Standardized tag constants\n\n  // ATOM Engine\n  AtomStats,\n  trustTierToString,\n\n  // SEAL v1\n  computeSealHash,\n  computeFeedbackLeafV1,\n  verifySealHash,\n  createSealParams,\n  validateSealInputs,\n  MAX_TAG_LEN,          // 32 bytes\n  MAX_ENDPOINT_LEN,     // 250 bytes\n  MAX_URI_LEN,          // 250 bytes\n\n  // OASF Taxonomy\n  getAllSkills,\n  getAllDomains,\n\n  // Tag helpers\n  isKnownTag,\n  getTagDescription,\n\n  // Signing\n  buildSignedPayload,\n  verifySignedPayload,\n  parseSignedPayload,\n  normalizeSignData,\n  createNonce,\n  canonicalizeJson,\n\n  // Value encoding\n  encodeReputationValue,\n  decodeToDecimalString,\n  decodeToNumber,\n\n  // Crypto utilities\n  keccak256,\n  sha256,\n  sha256Sync,          // Node.js only\n\n  // Hash-chain replay\n  replayFeedbackChain,\n  replayResponseChain,\n  replayRevokeChain,\n\n  // Indexer\n  IndexerClient,\n\n  // Endpoint crawler\n  EndpointCrawler,\n\n  // Error classes\n  IndexerError,\n  IndexerUnavailableError,\n  IndexerTimeoutError,\n  IndexerRateLimitError,\n  UnsupportedRpcError,\n  RpcNetworkError,\n} from '8004-solana';\n\nimport { Keypair, PublicKey } from '@solana/web3.js';"
      },
      {
        "title": "Read-only (no wallet needed)",
        "body": "const sdk = new SolanaSDK({ cluster: 'devnet' });"
      },
      {
        "title": "With signer (for write operations)",
        "body": "const signer = Keypair.fromSecretKey(\n  Uint8Array.from(JSON.parse(process.env.SOLANA_PRIVATE_KEY!))\n);\nconst sdk = new SolanaSDK({ signer });"
      },
      {
        "title": "With custom RPC (required for bulk queries)",
        "body": "const sdk = new SolanaSDK({\n  rpcUrl: 'https://your-helius-rpc.helius.dev',\n  signer,\n});"
      },
      {
        "title": "Full config",
        "body": "const sdk = new SolanaSDK({\n  cluster: 'devnet',\n  rpcUrl: 'https://...',\n  signer: keypair,\n  indexerUrl: 'https://xxx.supabase.co/rest/v1',\n  indexerApiKey: process.env.INDEXER_API_KEY, // if your indexer requires an API key, keep it in env\n  useIndexer: true,\n  indexerFallback: true,\n  forceOnChain: false,\n});"
      },
      {
        "title": "IPFS client",
        "body": "// Pinata (recommended)\nconst ipfsPinata = new IPFSClient({\n  pinataEnabled: true,\n  pinataJwt: process.env.PINATA_JWT!,\n});\n\n// Local node\nconst ipfsLocal = new IPFSClient({ url: 'http://localhost:5001' });"
      },
      {
        "title": "Step 1: Build metadata",
        "body": "const metadata = buildRegistrationFileJson({\n  name: 'My Agent',\n  description: 'Autonomous trading agent',\n  image: 'ipfs://QmImageCid...',\n  services: [\n    { type: ServiceType.MCP, value: 'https://my-agent.com/mcp' },\n    { type: ServiceType.A2A, value: 'https://my-agent.com/a2a' },\n  ],\n  skills: ['advanced_reasoning_planning/strategic_planning'],\n  domains: ['finance_and_business/finance'],\n  x402Support: true,\n});"
      },
      {
        "title": "Step 2: Upload to IPFS",
        "body": "const cid = await ipfs.addJson(metadata);"
      },
      {
        "title": "Step 3: Register on-chain",
        "body": "const result = await sdk.registerAgent(`ipfs://${cid}`);\n// result.asset   -> PublicKey (agent NFT address)\n// result.signature -> transaction signature\n// ATOM stats are auto-initialized"
      },
      {
        "title": "Step 4: Set operational wallet",
        "body": "const opWallet = Keypair.generate();\nawait sdk.setAgentWallet(result.asset, opWallet);"
      },
      {
        "title": "Collection (v0.6.x: single-collection)",
        "body": "All agents register into the base collection automatically. createCollection() and updateCollectionUri() are deprecated and return { success: false }.\n\nconst baseCollection = await sdk.getBaseCollection();"
      },
      {
        "title": "3. Read Agent Data",
        "body": "// Load agent\nconst agent = await sdk.loadAgent(assetPubkey);\n// agent.getOwnerPublicKey(), agent.getAgentWalletPublicKey(), agent.agent_uri, etc.\n\n// Check existence\nconst exists = await sdk.agentExists(assetPubkey);\n\n// Get owner\nconst owner = await sdk.getAgentOwner(assetPubkey);\n\n// Check ownership\nconst isMine = await sdk.isAgentOwner(assetPubkey, myPubkey);\n\n// On-chain metadata\nconst version = await sdk.getMetadata(assetPubkey, 'version');"
      },
      {
        "title": "Bulk queries (requires premium RPC: Helius, QuickNode, Alchemy)",
        "body": "const allAgents = await sdk.getAllAgents();\nconst withFeedbacks = await sdk.getAllAgents({ includeFeedbacks: true });\nconst myAgents = await sdk.getAgentsByOwner(ownerPubkey);"
      },
      {
        "title": "4. Update Agent",
        "body": "// Update metadata URI\nawait sdk.setAgentUri(assetPubkey, collectionPubkey, `ipfs://${newCid}`);\n\n// Set on-chain key-value metadata\nawait sdk.setMetadata(assetPubkey, 'version', '2.0.0');\n// First call: ~0.00319 SOL (PDA rent). Updates: ~0.000005 SOL (tx fee only)\n\n// Immutable metadata (permanent, cannot change or delete)\nawait sdk.setMetadata(assetPubkey, 'certification', 'audited-2026', true);\n\n// Delete metadata (recovers rent)\nawait sdk.deleteMetadata(assetPubkey, 'version');\n\n// Transfer ownership\nawait sdk.transferAgent(assetPubkey, collectionPubkey, newOwnerPubkey);\n\n// Sync owner after external NFT transfer\nawait sdk.syncOwner(assetPubkey);"
      },
      {
        "title": "Give feedback",
        "body": "// Decimal string auto-encodes: \"99.77\" -> { value: 9977n, valueDecimals: 2 }\nawait sdk.giveFeedback(assetPubkey, {\n  value: '99.77',\n  tag1: Tag.uptime,\n  tag2: Tag.day,\n  score: 95,                          // 0-100, optional\n  endpoint: '/api/v1/generate',       // optional, max 250 bytes\n  feedbackUri: `ipfs://${feedbackCid}`,\n  feedbackFileHash,                   // optional, 32 bytes Buffer (links file to SEAL)\n});"
      },
      {
        "title": "GiveFeedbackParams reference",
        "body": "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"
      },
      {
        "title": "Value encoding patterns",
        "body": "// Percentage with 2 decimals: 99.75%\nconst feedbackExamples = [\n{ value: '99.75', tag1: Tag.uptime },\n// -> encoded: value=9975n, valueDecimals=2\n\n// Milliseconds: 250ms\n{ value: 250, tag1: Tag.responseTime, valueDecimals: 0 },\n\n// Currency: $150.25\n{ value: '150.25', tag1: Tag.revenues, tag2: Tag.week },\n\n// Negative PnL: -$15.5\n{ value: '-15.5', tag1: Tag.tradingYield, tag2: Tag.month },\n\n// Binary check: reachable\n{ value: 1, tag1: Tag.reachable, valueDecimals: 0, score: 100 },\n\n// Quality rating (score only)\n{ value: '85', tag1: Tag.starred, score: 85 },\n];"
      },
      {
        "title": "Score behavior",
        "body": "score: 95 -> explicit quality score, used directly by ATOM\nscore: undefined/null -> ATOM infers from tag1 if it's a known tag (uptime, successRate, starred)\nTags without auto-score (responseTime, revenues, etc.) require explicit score for ATOM impact\n\nATOM-enabled tags (auto-score from value): starred, uptime, successRate\nContext-dependent tags (require explicit score): reachable, ownerVerified, responseTime, blocktimeFreshness, revenues, tradingYield"
      },
      {
        "title": "Read feedback",
        "body": "// Single feedback\nconst fb = await sdk.readFeedback(assetPubkey, clientPubkey, 0);\n// fb.value, fb.valueDecimals, fb.score, fb.tag1, fb.tag2, fb.sealHash\n\n// All feedbacks for agent (indexer-backed)\nconst all = await sdk.readAllFeedback(assetPubkey);\nconst withRevoked = await sdk.readAllFeedback(assetPubkey, true);\n\n// Last feedback index for a specific client (NOT a count)\nconst lastIndex = await sdk.getLastIndex(assetPubkey, clientPubkey);\nconst nextIndex = lastIndex + 1n; // if no feedback yet: lastIndex = -1n, nextIndex = 0n\n\n// All clients who gave feedback (indexer-backed)\nconst clients = await sdk.getClients(assetPubkey);\n\n// Via indexer (faster, no premium RPC needed)\nconst feedbacks = await sdk.getFeedbacksFromIndexer(assetPubkey, { limit: 50 });\nconst byEndpoint = await sdk.getFeedbacksByEndpoint('/api/generate');\nconst byTag = await sdk.getFeedbacksByTag('uptime');"
      },
      {
        "title": "Revoke feedback",
        "body": "// Requires the sealHash from the original feedback\nconst fb = await sdk.readFeedback(assetPubkey, clientPubkey, 0);\nawait sdk.revokeFeedback(assetPubkey, 0, fb.sealHash!);"
      },
      {
        "title": "Respond to feedback (as agent owner)",
        "body": "await sdk.appendResponse(\n  assetPubkey,\n  clientPubkey,\n  0,                          // feedbackIndex\n  fb.sealHash!,               // sealHash from the feedback\n  `ipfs://${responseCid}`,    // response URI\n);\n\n// Read responses\nconst responses = await sdk.readResponses(assetPubkey, clientPubkey, 0);\nconst count = await sdk.getResponseCount(assetPubkey, clientPubkey, 0);"
      },
      {
        "title": "Quick reputation summary",
        "body": "const summary = await sdk.getSummary(assetPubkey);\n// summary.averageScore      -> 0-100\n// summary.totalFeedbacks\n// summary.positiveCount     -> score >= 50\n// summary.negativeCount     -> score < 50\n\n// With filters\nconst filtered = await sdk.getSummary(assetPubkey, 70);  // minScore=70\nconst byClient = await sdk.getSummary(assetPubkey, undefined, clientPubkey);"
      },
      {
        "title": "ATOM stats (on-chain reputation engine)",
        "body": "const atom = await sdk.getAtomStats(assetPubkey);\nif (atom) {\n  atom.quality_score;             // 0-10000 (divide by 100 for percentage)\n  atom.confidence;                // 0-10000\n  atom.ema_score_fast;            // Fast EMA (reacts quickly)\n  atom.ema_score_slow;            // Slow EMA (stable baseline)\n  atom.ema_volatility;            // Score instability\n  atom.diversity_ratio;           // 0-255 (unique caller diversity)\n  atom.risk_score;                // 0-100\n  atom.trust_tier;                // 0-4\n\n  // Helper methods\n  atom.getQualityPercent();       // quality_score / 100\n  atom.getConfidencePercent();    // confidence / 100\n  atom.getAverageScore();         // ema_score_slow / 100\n  atom.estimateUniqueClients();   // HyperLogLog estimation\n  atom.getTrustTier();            // TrustTier enum\n}"
      },
      {
        "title": "Trust tier",
        "body": "const tier = await sdk.getTrustTier(assetPubkey);\n// TrustTier.Unrated   = 0\n// TrustTier.Bronze    = 1\n// TrustTier.Silver    = 2\n// TrustTier.Gold      = 3\n// TrustTier.Platinum  = 4\n\nconst name = trustTierToString(tier); // \"Gold\""
      },
      {
        "title": "Enriched summary (ATOM + raw feedback combined)",
        "body": "const enriched = await sdk.getEnrichedSummary(assetPubkey);\nif (enriched) {\n  enriched.trustTier;\n  enriched.qualityScore;     // 0-10000\n  enriched.confidence;       // 0-10000\n  enriched.riskScore;        // 0-100\n  enriched.diversityRatio;   // 0-255\n  enriched.uniqueCallers;    // HLL estimate\n  enriched.emaScoreFast;\n  enriched.emaScoreSlow;\n  enriched.volatility;\n  enriched.totalFeedbacks;\n  enriched.averageScore;     // 0-100\n  enriched.positiveCount;\n  enriched.negativeCount;\n}"
      },
      {
        "title": "Reputation from indexer",
        "body": "const rep = await sdk.getAgentReputationFromIndexer(assetPubkey);"
      },
      {
        "title": "Sign data with agent wallet",
        "body": "const signedJson = sdk.sign(assetPubkey, {\n  action: 'authorize',\n  target: 'task-123',\n  timestamp: Date.now(),\n});\n// Returns: JSON string of SignedPayloadV1"
      },
      {
        "title": "Verify signature",
        "body": "// From JSON string\nconst isValidFromJson = await sdk.verify(signedJson, assetPubkey);\n\n// From IPFS URI\nconst isValidFromIpfs = await sdk.verify('ipfs://QmPayload...', assetPubkey);\n\n// From HTTPS URL\nconst isValidFromHttps = await sdk.verify('https://example.com/signed.json', assetPubkey);\n\n// From file path\nconst isValidFromFile = await sdk.verify('./signed-payload.json', assetPubkey);\n\n// With explicit public key\nconst isValidWithPubkey = await sdk.verify(signedJson, assetPubkey, walletPubkey);"
      },
      {
        "title": "SignedPayloadV1 format",
        "body": "const exampleSignedPayload = {\n  v: 1,\n  alg: 'ed25519',\n  asset: 'base58...',     // agent asset pubkey\n  nonce: 'random-base58',\n  issuedAt: 1234567890,   // unix seconds\n  data: { action: 'authorize', target: 'task-123' }, // your payload\n  sig: 'base58...',       // Ed25519 signature\n};"
      },
      {
        "title": "8. Liveness Check",
        "body": "const defaultReport = await sdk.isItAlive(assetPubkey);\n// report.status: 'live' | 'partially' | 'not_live'\n// report.okCount, report.totalPinged, report.skippedCount\n// report.liveServices[], report.deadServices[], report.skippedServices[]\n\n// With options\nconst tunedReport = await sdk.isItAlive(assetPubkey, {\n  timeoutMs: 10000,\n  concurrency: 2,\n  treatAuthAsAlive: true,           // 401/403 = alive\n  includeTypes: [ServiceType.MCP],  // only check MCP endpoints\n});"
      },
      {
        "title": "9. SEAL v1 (Feedback Authenticity)",
        "body": "SEAL provides client-side hash computation matching on-chain Keccak256. Required for revokeFeedback() and appendResponse().\n\n// Build params (with optional feedbackFileHash)\nconst fileHash = await SolanaSDK.computeHash(JSON.stringify(feedbackFile));\nconst params = createSealParams(\n  9977n,                        // value (i64)\n  2,                            // decimals\n  85,                           // score (or null)\n  'uptime',                     // tag1\n  'day',                        // tag2\n  'https://api.example.com',    // endpoint (or null)\n  'ipfs://QmFeedback...',       // feedbackUri\n  fileHash,                     // feedbackFileHash (or null)\n);\n\n// Validate inputs before hashing (throws on invalid params)\nvalidateSealInputs(params);\n\n// Compute hash\nconst sealHash = computeSealHash(params);  // Buffer, 32 bytes (Keccak256)\n\n// Verify\nconst valid = verifySealHash({ ...params, sealHash });  // true\n\n// Compute feedback leaf (for hash-chain verification)\nconst leaf = computeFeedbackLeafV1(\n  assetPubkey.toBuffer(),\n  clientPubkey.toBuffer(),\n  0n,           // feedbackIndex\n  sealHash,\n  12345n,       // slot\n);"
      },
      {
        "title": "Field size limits",
        "body": "FieldMax bytesConstanttag1, tag232 UTF-8MAX_TAG_LENendpoint250 UTF-8MAX_ENDPOINT_LENfeedbackUri250 UTF-8MAX_URI_LENfeedbackFileHash32 exact-"
      },
      {
        "title": "Quick check (O(1))",
        "body": "const integrity = await sdk.verifyIntegrity(assetPubkey);\n// integrity.valid        -> boolean\n// integrity.status       -> 'valid' | 'syncing' | 'corrupted' | 'error'\n// integrity.trustworthy  -> boolean\n// integrity.totalLag     -> bigint (blocks behind)\n// integrity.chains.feedback, .response, .revoke"
      },
      {
        "title": "Deep verification (spot checks)",
        "body": "const deep = await sdk.verifyIntegrityDeep(assetPubkey, {\n  spotChecks: 10,\n  checkBoundaries: true,\n  verifyContent: false,  // true = also verify IPFS content hashes (slow)\n});\n// deep.spotChecksPassed, deep.missingItems, deep.modifiedItems"
      },
      {
        "title": "Full hash-chain replay",
        "body": "const full = await sdk.verifyIntegrityFull(assetPubkey, {\n  onProgress: (chain, count, total) => {\n    console.log(`${chain}: ${count}/${total}`);\n  },\n});"
      },
      {
        "title": "Search agents (via indexer)",
        "body": "const results = await sdk.searchAgents({\n  owner: 'base58...',\n  collection: 'base58...',\n  wallet: 'base58...',\n  limit: 20,\n  offset: 0,\n});"
      },
      {
        "title": "Leaderboard",
        "body": "const top = await sdk.getLeaderboard({\n  minTier: 2,        // Silver+\n  limit: 50,\n  collection: 'base58...',\n});"
      },
      {
        "title": "Global stats",
        "body": "const global = await sdk.getGlobalStats();\n// global.total_agents, total_feedbacks, platinum_agents, gold_agents, avg_quality"
      },
      {
        "title": "Find agent by wallet",
        "body": "const agent = await sdk.getAgentByWallet(walletPubkey.toBase58());"
      },
      {
        "title": "Endpoint crawler",
        "body": "const crawler = new EndpointCrawler(5000);\nconst mcp = await crawler.fetchMcpCapabilities('https://agent.com/mcp');\n// mcp.mcpTools, mcp.mcpPrompts, mcp.mcpResources\n\nconst a2a = await crawler.fetchA2aCapabilities('https://agent.com');\n// a2a.a2aSkills"
      },
      {
        "title": "12. SDK Introspection",
        "body": "// Chain identity (CAIP-2 format)\nconst chain = await sdk.chainId();       // 'solana-devnet'\nconst cluster = sdk.getCluster();         // 'devnet' | 'mainnet-beta' | 'testnet'\n\n// Program IDs for all registries\nconst programs = sdk.getProgramIds();\n// programs.identityRegistry   -> PublicKey\n// programs.reputationRegistry -> PublicKey\n// programs.validationRegistry -> PublicKey\n\n// Registry addresses as strings (parity with agent0-ts)\nconst regs = sdk.registries();\n// { IDENTITY: 'base58...', REPUTATION: 'base58...', VALIDATION: 'base58...' }\n\n// RPC info\nconst rpcUrl = sdk.getRpcUrl();\nconst isDefaultRpc = sdk.isUsingDefaultDevnetRpc();\nconst canBulkQuery = sdk.supportsAdvancedQueries();\nconst readOnly = sdk.isReadOnly;\n\n// Base collection (single-collection architecture in v0.6.x)\nconst base = await sdk.getBaseCollection();\n\n// Advanced: access underlying clients\nconst solanaClient = sdk.getSolanaClient();\nconst feedbackMgr = sdk.getFeedbackManager();"
      },
      {
        "title": "Category tags (tag1)",
        "body": "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"
      },
      {
        "title": "Period tags (tag2)",
        "body": "ConstantStringTag.day'day'Tag.week'week'Tag.month'month'Tag.year'year'"
      },
      {
        "title": "x402 tags (tag1) - Client -> Agent",
        "body": "ConstantStringTag.x402ResourceDelivered'x402-resource-delivered'Tag.x402DeliveryFailed'x402-delivery-failed'Tag.x402DeliveryTimeout'x402-delivery-timeout'Tag.x402QualityIssue'x402-quality-issue'"
      },
      {
        "title": "x402 tags (tag1) - Agent -> Client",
        "body": "ConstantStringTag.x402GoodPayer'x402-good-payer'Tag.x402PaymentFailed'x402-payment-failed'Tag.x402InsufficientFunds'x402-insufficient-funds'Tag.x402InvalidSignature'x402-invalid-signature'"
      },
      {
        "title": "x402 network tags (tag2)",
        "body": "ConstantStringTag.x402Evm'exact-evm'Tag.x402Svm'exact-svm'"
      },
      {
        "title": "Tag utilities",
        "body": "isKnownTag('uptime');              // true\nisKnownTag('custom-metric');       // false\ngetTagDescription('successRate');   // 'Task completion success percentage'\n\nCustom tags are fully supported - any string up to 32 UTF-8 bytes."
      },
      {
        "title": "14. OASF Taxonomy",
        "body": "// List taxonomy slugs\nconst skills = getAllSkills();   // 136 skills\nconst domains = getAllDomains(); // 204 domains"
      },
      {
        "title": "15. Hash Utilities",
        "body": "// SHA-256 (async, browser-compatible via WebCrypto)\nconst hash = await SolanaSDK.computeHash('My feedback content');\nconst bufHash = await SolanaSDK.computeHash(Buffer.from(jsonData));\n// Returns: Buffer (32 bytes)\n\n// URI hash (zeros for IPFS/Arweave since CID is already content-addressable)\nconst uriHash = await SolanaSDK.computeUriHash('https://example.com/data.json');\n// -> SHA-256 of the URI string\nconst ipfsHash = await SolanaSDK.computeUriHash('ipfs://Qm...');\n// -> Buffer.alloc(32) (zeros)\n\n// Keccak-256 (synchronous, used by SEAL v1)\nimport { keccak256 } from '8004-solana';\nconst k = keccak256(Buffer.from('data'));\n\n// SHA-256 sync (CJS context only — uses require('crypto'), throws in pure ESM or browser)\nimport { sha256Sync } from '8004-solana';\nconst s = sha256Sync('data');  // Uint8Array (32 bytes)"
      },
      {
        "title": "16. Value Encoding",
        "body": "import {\n  encodeReputationValue,\n  decodeToDecimalString,\n  decodeToNumber,\n} from '8004-solana';\n\n// Encode: decimal string -> { value: bigint, valueDecimals: number }\nconst encoded = encodeReputationValue('99.77');\n// { value: 9977n, valueDecimals: 2, normalized: '99.77' }\n\nconst neg = encodeReputationValue('-15.5');\n// { value: -155n, valueDecimals: 1, normalized: '-15.5' }\n\nconst raw = encodeReputationValue(9977n, 2);\n// { value: 9977n, valueDecimals: 2, normalized: '99.77' }\n\n// Decode: bigint + decimals -> string or number\ndecodeToDecimalString(9977n, 2);   // '99.77'\ndecodeToDecimalString(-155n, 1);   // '-15.5'\ndecodeToNumber(9977n, 2);          // 99.77\n\n// Limits: max 6 decimal places, clamped to i64 range"
      },
      {
        "title": "17. Canonical JSON & Signing Utilities",
        "body": "import {\n  canonicalizeJson,\n  normalizeSignData,\n  createNonce,\n} from '8004-solana';\n\n// RFC 8785 canonical JSON (deterministic key ordering, no whitespace)\ncanonicalizeJson({ b: 2, a: 1 });  // '{\"a\":1,\"b\":2}'\n\n// Normalize data for signing (handles BigInt, PublicKey, Date, Buffer)\nconst normalized = normalizeSignData({\n  amount: 100n,           // -> { $bigint: '100' }\n  key: somePubkey,        // -> { $pubkey: 'base58...' }\n  when: new Date(),       // -> { $date: 'ISO...' }\n  data: Buffer.from([1]), // -> { $bytes: 'AQ==', encoding: 'base64' }\n});\n\n// Cryptographic nonce generation (base58-encoded random bytes)\nconst nonce = createNonce();     // 16 bytes default\nconst nonce32 = createNonce(32); // 32 bytes"
      },
      {
        "title": "18. IPFS Operations",
        "body": "// Add data\nconst jsonCid = await ipfs.addJson({ key: 'value' });\nconst rawCid = await ipfs.add('raw string data');\nconst fileCid = await ipfs.addFile('./image.png');\n\n// Add registration file (normalizes and formats)\nconst registrationCid = await ipfs.addRegistrationFile(registrationFile);\n\n// Retrieve\nconst data = await ipfs.get(jsonCid);              // raw string\nconst json = await ipfs.getJson(jsonCid);          // parsed JSON\nconst reg = await ipfs.getRegistrationFile(registrationCid); // RegistrationFile\n\n// Supports ipfs:// prefix\nconst ipfsPrefixedData = await ipfs.get('ipfs://QmAbc...');\n\n// Pin/unpin\nawait ipfs.pin(fileCid);\nawait ipfs.unpin(fileCid);\n\n// Cleanup\nawait ipfs.close();"
      },
      {
        "title": "19. Server Mode (skipSend)",
        "body": "For browser wallets or external signing:\n\n// Get unsigned transaction\nconst assetKeypair = Keypair.generate();\nconst prepared = await sdk.registerAgent(uri, undefined, {\n  skipSend: true,\n  signer: ownerPubkey,              // required when SDK has no signer\n  assetPubkey: assetKeypair.publicKey, // required in skipSend mode\n});\n// prepared.transaction -> base64 serialized unsigned transaction\n// prepared.signer -> base58 of the required signer\n\n// For agent wallet (browser wallet flow)\nconst { message, complete } = await sdk.prepareSetAgentWallet(\n  assetPubkey,\n  walletPubkey,\n  { signer: ownerPubkey } // optional if SDK was initialized with signer\n);\nconst signature = await phantomWallet.signMessage(message);\nawait complete(signature);\n\nAll write methods accept { skipSend: true } in their options."
      },
      {
        "title": "20. Indexer Client (Direct Access)",
        "body": "const indexer = sdk.getIndexerClient();\n\n// Check availability\nconst available = await sdk.isIndexerAvailable();\n\n// Direct queries\nconst agents = await indexer.getAgentsByOwner('base58...');\nconst feedbacks = await indexer.getFeedbacks('base58...', { limit: 100 });\nconst leaderboard = await indexer.getLeaderboard({ minTier: 3 });"
      },
      {
        "title": "Wait for indexer sync after write",
        "body": "await sdk.giveFeedback(assetPubkey, feedbackParams);\n\n// Poll until indexer catches up (returns true if synced, false on timeout)\nconst synced = await sdk.waitForIndexerSync(\n  async () => {\n    const fbs = await sdk.getFeedbacksFromIndexer(assetPubkey);\n    return fbs.length >= expectedCount;\n  },\n  { timeout: 30000 }  // ms, default 30s\n);"
      },
      {
        "title": "21. Error Handling",
        "body": "import {\n  IndexerError,\n  IndexerUnavailableError,\n  IndexerTimeoutError,\n  IndexerRateLimitError,\n  UnsupportedRpcError,\n  RpcNetworkError,\n} from '8004-solana';\n\ntry {\n  const agents = await sdk.getAllAgents();\n} catch (e) {\n  if (e instanceof UnsupportedRpcError) {\n    // Default RPC doesn't support getProgramAccounts\n    // Use Helius, QuickNode, or Alchemy\n  }\n  if (e instanceof IndexerUnavailableError) {\n    // Indexer is down, SDK falls back to RPC if indexerFallback=true\n  }\n  if (e instanceof IndexerRateLimitError) {\n    // Back off and retry\n  }\n}"
      },
      {
        "title": "Methods requiring premium RPC",
        "body": "getAllAgents(), getAgentsByOwner(), getCollectionAgents(), getCollections()\n\nIndexer-backed reads (readAllFeedback(), getClients(), getLastIndex(), readResponses()) do not require premium RPC, but they do require a reachable indexer."
      },
      {
        "title": "22. Operation Costs (Solana devnet)",
        "body": "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"
      },
      {
        "title": "Monitor agent health",
        "body": "const report = await sdk.isItAlive(assetPubkey);\nif (report.status !== 'live') {\n  await sdk.giveFeedback(assetPubkey, {\n    value: 0,\n    valueDecimals: 0,\n    tag1: Tag.reachable,\n    score: 0,\n    feedbackUri: `ipfs://${alertCid}`,\n  });\n}"
      },
      {
        "title": "Periodic uptime reporting",
        "body": "const uptimePercent = calculateUptime(); // your logic\nawait sdk.giveFeedback(assetPubkey, {\n  value: uptimePercent.toFixed(2),  // \"99.75\" auto-encodes\n  tag1: Tag.uptime,\n  tag2: Tag.day,\n  feedbackUri: `ipfs://${reportCid}`,\n});"
      },
      {
        "title": "Trust-gated interaction",
        "body": "const tier = await sdk.getTrustTier(assetPubkey);\nif (tier < TrustTier.Silver) {\n  throw new Error('Agent trust too low for this operation');\n}"
      },
      {
        "title": "x402 payment feedback (full flow)",
        "body": "// 1. Build the feedback file JSON (off-chain proof of payment)\nconst feedbackFile = {\n  version: '1.0',\n  type: 'x402-feedback',\n  agent: assetPubkey.toBase58(),\n  client: clientPubkey.toBase58(),\n  endpoint: '/api/generate',\n  timestamp: new Date().toISOString(),\n  proofOfPayment: {\n    txHash: 'base58-tx-signature...',\n    fromAddress: clientPubkey.toBase58(),\n    toAddress: agentWalletPubkey.toBase58(),\n    amount: '0.001',\n    token: 'SOL',\n    chainId: await sdk.chainId(),   // 'solana-devnet'\n  },\n  settlement: {\n    success: true,\n    network: 'solana',\n    settledAt: new Date().toISOString(),\n  },\n  result: {\n    delivered: true,\n    latencyMs: 230,\n    quality: 'good',\n  },\n};\n\n// 2. Upload to IPFS\nconst feedbackCid = await ipfs.addJson(feedbackFile);\n\n// 3. Optionally compute content hash for SEAL integrity\nconst feedbackFileHash = await SolanaSDK.computeHash(\n  JSON.stringify(feedbackFile)\n);\n\n// 4. Submit on-chain feedback with proof link\nawait sdk.giveFeedback(assetPubkey, {\n  value: '100.00',\n  tag1: Tag.x402ResourceDelivered,\n  tag2: Tag.x402Svm,\n  score: 95,\n  endpoint: '/api/generate',\n  feedbackUri: `ipfs://${feedbackCid}`,\n  feedbackFileHash,  // links file content to on-chain SEAL\n});\n\n// Agent-side: report good payer\nawait sdk.giveFeedback(clientAgentPubkey, {\n  value: '1',\n  valueDecimals: 0,\n  tag1: Tag.x402GoodPayer,\n  tag2: Tag.x402Svm,\n  score: 100,\n  feedbackUri: `ipfs://${payerProofCid}`,\n});"
      },
      {
        "title": "Verify before trusting indexer data",
        "body": "const integrity = await sdk.verifyIntegrity(assetPubkey);\nif (!integrity.trustworthy) {\n  console.warn(`Indexer data not trustworthy: ${integrity.status}`);\n  // Fall back to on-chain queries\n}"
      },
      {
        "title": "24. Program IDs",
        "body": "import {\n  PROGRAM_ID,            // Agent Registry: 8oo48pya1SZD23ZhzoNMhxR2UGb8BRa41Su4qP9EuaWm\n  MPL_CORE_PROGRAM_ID,   // Metaplex Core: CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d\n  ATOM_ENGINE_PROGRAM_ID, // ATOM: AToM1iKaniUCuWfHd5WQy5aLgJYWMiKq78NtNJmtzSXJ\n} from '8004-solana';"
      }
    ],
    "body": "8004-solana SDK Skill\n\nYou 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.\n\nVersion note (SDK 0.6.x):\n\nSingle-collection architecture is active. createCollection() and updateCollectionUri() are deprecated and return { success: false, error }.\nFeedback reads (readAllFeedback, getClients, getLastIndex, readFeedback, etc.) rely on the indexer.\nInstall\nnpm install 8004-solana @solana/web3.js\n\nImports\nimport {\n  // Core SDK\n  SolanaSDK,\n  IPFSClient,\n\n  // Builders\n  buildRegistrationFileJson,\n\n  // Enums & Types\n  ServiceType,       // MCP, A2A, ENS, DID, WALLET, OASF\n  TrustTier,         // Unrated=0, Bronze=1, Silver=2, Gold=3, Platinum=4\n  Tag,               // Standardized tag constants\n\n  // ATOM Engine\n  AtomStats,\n  trustTierToString,\n\n  // SEAL v1\n  computeSealHash,\n  computeFeedbackLeafV1,\n  verifySealHash,\n  createSealParams,\n  validateSealInputs,\n  MAX_TAG_LEN,          // 32 bytes\n  MAX_ENDPOINT_LEN,     // 250 bytes\n  MAX_URI_LEN,          // 250 bytes\n\n  // OASF Taxonomy\n  getAllSkills,\n  getAllDomains,\n\n  // Tag helpers\n  isKnownTag,\n  getTagDescription,\n\n  // Signing\n  buildSignedPayload,\n  verifySignedPayload,\n  parseSignedPayload,\n  normalizeSignData,\n  createNonce,\n  canonicalizeJson,\n\n  // Value encoding\n  encodeReputationValue,\n  decodeToDecimalString,\n  decodeToNumber,\n\n  // Crypto utilities\n  keccak256,\n  sha256,\n  sha256Sync,          // Node.js only\n\n  // Hash-chain replay\n  replayFeedbackChain,\n  replayResponseChain,\n  replayRevokeChain,\n\n  // Indexer\n  IndexerClient,\n\n  // Endpoint crawler\n  EndpointCrawler,\n\n  // Error classes\n  IndexerError,\n  IndexerUnavailableError,\n  IndexerTimeoutError,\n  IndexerRateLimitError,\n  UnsupportedRpcError,\n  RpcNetworkError,\n} from '8004-solana';\n\nimport { Keypair, PublicKey } from '@solana/web3.js';\n\n1. SDK Setup\nRead-only (no wallet needed)\nconst sdk = new SolanaSDK({ cluster: 'devnet' });\n\nWith signer (for write operations)\nconst signer = Keypair.fromSecretKey(\n  Uint8Array.from(JSON.parse(process.env.SOLANA_PRIVATE_KEY!))\n);\nconst sdk = new SolanaSDK({ signer });\n\nWith custom RPC (required for bulk queries)\nconst sdk = new SolanaSDK({\n  rpcUrl: 'https://your-helius-rpc.helius.dev',\n  signer,\n});\n\nFull config\nconst sdk = new SolanaSDK({\n  cluster: 'devnet',\n  rpcUrl: 'https://...',\n  signer: keypair,\n  indexerUrl: 'https://xxx.supabase.co/rest/v1',\n  indexerApiKey: process.env.INDEXER_API_KEY, // if your indexer requires an API key, keep it in env\n  useIndexer: true,\n  indexerFallback: true,\n  forceOnChain: false,\n});\n\nIPFS client\n// Pinata (recommended)\nconst ipfsPinata = new IPFSClient({\n  pinataEnabled: true,\n  pinataJwt: process.env.PINATA_JWT!,\n});\n\n// Local node\nconst ipfsLocal = new IPFSClient({ url: 'http://localhost:5001' });\n\n2. Register an Agent\nStep 1: Build metadata\nconst metadata = buildRegistrationFileJson({\n  name: 'My Agent',\n  description: 'Autonomous trading agent',\n  image: 'ipfs://QmImageCid...',\n  services: [\n    { type: ServiceType.MCP, value: 'https://my-agent.com/mcp' },\n    { type: ServiceType.A2A, value: 'https://my-agent.com/a2a' },\n  ],\n  skills: ['advanced_reasoning_planning/strategic_planning'],\n  domains: ['finance_and_business/finance'],\n  x402Support: true,\n});\n\nStep 2: Upload to IPFS\nconst cid = await ipfs.addJson(metadata);\n\nStep 3: Register on-chain\nconst result = await sdk.registerAgent(`ipfs://${cid}`);\n// result.asset   -> PublicKey (agent NFT address)\n// result.signature -> transaction signature\n// ATOM stats are auto-initialized\n\nStep 4: Set operational wallet\nconst opWallet = Keypair.generate();\nawait sdk.setAgentWallet(result.asset, opWallet);\n\nCollection (v0.6.x: single-collection)\n\nAll agents register into the base collection automatically. createCollection() and updateCollectionUri() are deprecated and return { success: false }.\n\nconst baseCollection = await sdk.getBaseCollection();\n\n3. Read Agent Data\n// Load agent\nconst agent = await sdk.loadAgent(assetPubkey);\n// agent.getOwnerPublicKey(), agent.getAgentWalletPublicKey(), agent.agent_uri, etc.\n\n// Check existence\nconst exists = await sdk.agentExists(assetPubkey);\n\n// Get owner\nconst owner = await sdk.getAgentOwner(assetPubkey);\n\n// Check ownership\nconst isMine = await sdk.isAgentOwner(assetPubkey, myPubkey);\n\n// On-chain metadata\nconst version = await sdk.getMetadata(assetPubkey, 'version');\n\nBulk queries (requires premium RPC: Helius, QuickNode, Alchemy)\nconst allAgents = await sdk.getAllAgents();\nconst withFeedbacks = await sdk.getAllAgents({ includeFeedbacks: true });\nconst myAgents = await sdk.getAgentsByOwner(ownerPubkey);\n\n4. Update Agent\n// Update metadata URI\nawait sdk.setAgentUri(assetPubkey, collectionPubkey, `ipfs://${newCid}`);\n\n// Set on-chain key-value metadata\nawait sdk.setMetadata(assetPubkey, 'version', '2.0.0');\n// First call: ~0.00319 SOL (PDA rent). Updates: ~0.000005 SOL (tx fee only)\n\n// Immutable metadata (permanent, cannot change or delete)\nawait sdk.setMetadata(assetPubkey, 'certification', 'audited-2026', true);\n\n// Delete metadata (recovers rent)\nawait sdk.deleteMetadata(assetPubkey, 'version');\n\n// Transfer ownership\nawait sdk.transferAgent(assetPubkey, collectionPubkey, newOwnerPubkey);\n\n// Sync owner after external NFT transfer\nawait sdk.syncOwner(assetPubkey);\n\n5. Feedback System\nGive feedback\n// Decimal string auto-encodes: \"99.77\" -> { value: 9977n, valueDecimals: 2 }\nawait sdk.giveFeedback(assetPubkey, {\n  value: '99.77',\n  tag1: Tag.uptime,\n  tag2: Tag.day,\n  score: 95,                          // 0-100, optional\n  endpoint: '/api/v1/generate',       // optional, max 250 bytes\n  feedbackUri: `ipfs://${feedbackCid}`,\n  feedbackFileHash,                   // optional, 32 bytes Buffer (links file to SEAL)\n});\n\nGiveFeedbackParams reference\nField\tType\tRequired\tDescription\nvalue\tstring | number | bigint\tYes\tMetric value. Strings auto-encode decimals (\"99.77\" -> 9977n, 2)\nvalueDecimals\tnumber (0-6)\tNo\tOnly needed for raw int/bigint. Auto-detected for strings\nscore\tnumber (0-100)\tNo\tExplicit ATOM score. If omitted, inferred from tag1\ntag1\tstring\tNo\tCategory tag (max 32 UTF-8 bytes)\ntag2\tstring\tNo\tPeriod/network tag (max 32 UTF-8 bytes)\nendpoint\tstring\tNo\tEndpoint used (max 250 UTF-8 bytes)\nfeedbackUri\tstring\tYes\tURI to detailed feedback file (IPFS/HTTPS, max 250 bytes)\nfeedbackFileHash\tBuffer\tNo\tSHA-256 of feedback file content (32 bytes). Binds file to on-chain SEAL\nValue encoding patterns\n// Percentage with 2 decimals: 99.75%\nconst feedbackExamples = [\n{ value: '99.75', tag1: Tag.uptime },\n// -> encoded: value=9975n, valueDecimals=2\n\n// Milliseconds: 250ms\n{ value: 250, tag1: Tag.responseTime, valueDecimals: 0 },\n\n// Currency: $150.25\n{ value: '150.25', tag1: Tag.revenues, tag2: Tag.week },\n\n// Negative PnL: -$15.5\n{ value: '-15.5', tag1: Tag.tradingYield, tag2: Tag.month },\n\n// Binary check: reachable\n{ value: 1, tag1: Tag.reachable, valueDecimals: 0, score: 100 },\n\n// Quality rating (score only)\n{ value: '85', tag1: Tag.starred, score: 85 },\n];\n\nScore behavior\nscore: 95 -> explicit quality score, used directly by ATOM\nscore: undefined/null -> ATOM infers from tag1 if it's a known tag (uptime, successRate, starred)\nTags without auto-score (responseTime, revenues, etc.) require explicit score for ATOM impact\n\nATOM-enabled tags (auto-score from value): starred, uptime, successRate Context-dependent tags (require explicit score): reachable, ownerVerified, responseTime, blocktimeFreshness, revenues, tradingYield\n\nRead feedback\n// Single feedback\nconst fb = await sdk.readFeedback(assetPubkey, clientPubkey, 0);\n// fb.value, fb.valueDecimals, fb.score, fb.tag1, fb.tag2, fb.sealHash\n\n// All feedbacks for agent (indexer-backed)\nconst all = await sdk.readAllFeedback(assetPubkey);\nconst withRevoked = await sdk.readAllFeedback(assetPubkey, true);\n\n// Last feedback index for a specific client (NOT a count)\nconst lastIndex = await sdk.getLastIndex(assetPubkey, clientPubkey);\nconst nextIndex = lastIndex + 1n; // if no feedback yet: lastIndex = -1n, nextIndex = 0n\n\n// All clients who gave feedback (indexer-backed)\nconst clients = await sdk.getClients(assetPubkey);\n\n// Via indexer (faster, no premium RPC needed)\nconst feedbacks = await sdk.getFeedbacksFromIndexer(assetPubkey, { limit: 50 });\nconst byEndpoint = await sdk.getFeedbacksByEndpoint('/api/generate');\nconst byTag = await sdk.getFeedbacksByTag('uptime');\n\nRevoke feedback\n// Requires the sealHash from the original feedback\nconst fb = await sdk.readFeedback(assetPubkey, clientPubkey, 0);\nawait sdk.revokeFeedback(assetPubkey, 0, fb.sealHash!);\n\nRespond to feedback (as agent owner)\nawait sdk.appendResponse(\n  assetPubkey,\n  clientPubkey,\n  0,                          // feedbackIndex\n  fb.sealHash!,               // sealHash from the feedback\n  `ipfs://${responseCid}`,    // response URI\n);\n\n// Read responses\nconst responses = await sdk.readResponses(assetPubkey, clientPubkey, 0);\nconst count = await sdk.getResponseCount(assetPubkey, clientPubkey, 0);\n\n6. Reputation & ATOM Engine\nQuick reputation summary\nconst summary = await sdk.getSummary(assetPubkey);\n// summary.averageScore      -> 0-100\n// summary.totalFeedbacks\n// summary.positiveCount     -> score >= 50\n// summary.negativeCount     -> score < 50\n\n// With filters\nconst filtered = await sdk.getSummary(assetPubkey, 70);  // minScore=70\nconst byClient = await sdk.getSummary(assetPubkey, undefined, clientPubkey);\n\nATOM stats (on-chain reputation engine)\nconst atom = await sdk.getAtomStats(assetPubkey);\nif (atom) {\n  atom.quality_score;             // 0-10000 (divide by 100 for percentage)\n  atom.confidence;                // 0-10000\n  atom.ema_score_fast;            // Fast EMA (reacts quickly)\n  atom.ema_score_slow;            // Slow EMA (stable baseline)\n  atom.ema_volatility;            // Score instability\n  atom.diversity_ratio;           // 0-255 (unique caller diversity)\n  atom.risk_score;                // 0-100\n  atom.trust_tier;                // 0-4\n\n  // Helper methods\n  atom.getQualityPercent();       // quality_score / 100\n  atom.getConfidencePercent();    // confidence / 100\n  atom.getAverageScore();         // ema_score_slow / 100\n  atom.estimateUniqueClients();   // HyperLogLog estimation\n  atom.getTrustTier();            // TrustTier enum\n}\n\nTrust tier\nconst tier = await sdk.getTrustTier(assetPubkey);\n// TrustTier.Unrated   = 0\n// TrustTier.Bronze    = 1\n// TrustTier.Silver    = 2\n// TrustTier.Gold      = 3\n// TrustTier.Platinum  = 4\n\nconst name = trustTierToString(tier); // \"Gold\"\n\nEnriched summary (ATOM + raw feedback combined)\nconst enriched = await sdk.getEnrichedSummary(assetPubkey);\nif (enriched) {\n  enriched.trustTier;\n  enriched.qualityScore;     // 0-10000\n  enriched.confidence;       // 0-10000\n  enriched.riskScore;        // 0-100\n  enriched.diversityRatio;   // 0-255\n  enriched.uniqueCallers;    // HLL estimate\n  enriched.emaScoreFast;\n  enriched.emaScoreSlow;\n  enriched.volatility;\n  enriched.totalFeedbacks;\n  enriched.averageScore;     // 0-100\n  enriched.positiveCount;\n  enriched.negativeCount;\n}\n\nReputation from indexer\nconst rep = await sdk.getAgentReputationFromIndexer(assetPubkey);\n\n7. Signing & Verification\nSign data with agent wallet\nconst signedJson = sdk.sign(assetPubkey, {\n  action: 'authorize',\n  target: 'task-123',\n  timestamp: Date.now(),\n});\n// Returns: JSON string of SignedPayloadV1\n\nVerify signature\n// From JSON string\nconst isValidFromJson = await sdk.verify(signedJson, assetPubkey);\n\n// From IPFS URI\nconst isValidFromIpfs = await sdk.verify('ipfs://QmPayload...', assetPubkey);\n\n// From HTTPS URL\nconst isValidFromHttps = await sdk.verify('https://example.com/signed.json', assetPubkey);\n\n// From file path\nconst isValidFromFile = await sdk.verify('./signed-payload.json', assetPubkey);\n\n// With explicit public key\nconst isValidWithPubkey = await sdk.verify(signedJson, assetPubkey, walletPubkey);\n\nSignedPayloadV1 format\nconst exampleSignedPayload = {\n  v: 1,\n  alg: 'ed25519',\n  asset: 'base58...',     // agent asset pubkey\n  nonce: 'random-base58',\n  issuedAt: 1234567890,   // unix seconds\n  data: { action: 'authorize', target: 'task-123' }, // your payload\n  sig: 'base58...',       // Ed25519 signature\n};\n\n8. Liveness Check\nconst defaultReport = await sdk.isItAlive(assetPubkey);\n// report.status: 'live' | 'partially' | 'not_live'\n// report.okCount, report.totalPinged, report.skippedCount\n// report.liveServices[], report.deadServices[], report.skippedServices[]\n\n// With options\nconst tunedReport = await sdk.isItAlive(assetPubkey, {\n  timeoutMs: 10000,\n  concurrency: 2,\n  treatAuthAsAlive: true,           // 401/403 = alive\n  includeTypes: [ServiceType.MCP],  // only check MCP endpoints\n});\n\n9. SEAL v1 (Feedback Authenticity)\n\nSEAL provides client-side hash computation matching on-chain Keccak256. Required for revokeFeedback() and appendResponse().\n\n// Build params (with optional feedbackFileHash)\nconst fileHash = await SolanaSDK.computeHash(JSON.stringify(feedbackFile));\nconst params = createSealParams(\n  9977n,                        // value (i64)\n  2,                            // decimals\n  85,                           // score (or null)\n  'uptime',                     // tag1\n  'day',                        // tag2\n  'https://api.example.com',    // endpoint (or null)\n  'ipfs://QmFeedback...',       // feedbackUri\n  fileHash,                     // feedbackFileHash (or null)\n);\n\n// Validate inputs before hashing (throws on invalid params)\nvalidateSealInputs(params);\n\n// Compute hash\nconst sealHash = computeSealHash(params);  // Buffer, 32 bytes (Keccak256)\n\n// Verify\nconst valid = verifySealHash({ ...params, sealHash });  // true\n\n// Compute feedback leaf (for hash-chain verification)\nconst leaf = computeFeedbackLeafV1(\n  assetPubkey.toBuffer(),\n  clientPubkey.toBuffer(),\n  0n,           // feedbackIndex\n  sealHash,\n  12345n,       // slot\n);\n\nField size limits\nField\tMax bytes\tConstant\ntag1, tag2\t32 UTF-8\tMAX_TAG_LEN\nendpoint\t250 UTF-8\tMAX_ENDPOINT_LEN\nfeedbackUri\t250 UTF-8\tMAX_URI_LEN\nfeedbackFileHash\t32 exact\t-\n10. Integrity Verification\nQuick check (O(1))\nconst integrity = await sdk.verifyIntegrity(assetPubkey);\n// integrity.valid        -> boolean\n// integrity.status       -> 'valid' | 'syncing' | 'corrupted' | 'error'\n// integrity.trustworthy  -> boolean\n// integrity.totalLag     -> bigint (blocks behind)\n// integrity.chains.feedback, .response, .revoke\n\nDeep verification (spot checks)\nconst deep = await sdk.verifyIntegrityDeep(assetPubkey, {\n  spotChecks: 10,\n  checkBoundaries: true,\n  verifyContent: false,  // true = also verify IPFS content hashes (slow)\n});\n// deep.spotChecksPassed, deep.missingItems, deep.modifiedItems\n\nFull hash-chain replay\nconst full = await sdk.verifyIntegrityFull(assetPubkey, {\n  onProgress: (chain, count, total) => {\n    console.log(`${chain}: ${count}/${total}`);\n  },\n});\n\n11. Search & Discovery\nSearch agents (via indexer)\nconst results = await sdk.searchAgents({\n  owner: 'base58...',\n  collection: 'base58...',\n  wallet: 'base58...',\n  limit: 20,\n  offset: 0,\n});\n\nLeaderboard\nconst top = await sdk.getLeaderboard({\n  minTier: 2,        // Silver+\n  limit: 50,\n  collection: 'base58...',\n});\n\nGlobal stats\nconst global = await sdk.getGlobalStats();\n// global.total_agents, total_feedbacks, platinum_agents, gold_agents, avg_quality\n\nFind agent by wallet\nconst agent = await sdk.getAgentByWallet(walletPubkey.toBase58());\n\nEndpoint crawler\nconst crawler = new EndpointCrawler(5000);\nconst mcp = await crawler.fetchMcpCapabilities('https://agent.com/mcp');\n// mcp.mcpTools, mcp.mcpPrompts, mcp.mcpResources\n\nconst a2a = await crawler.fetchA2aCapabilities('https://agent.com');\n// a2a.a2aSkills\n\n12. SDK Introspection\n// Chain identity (CAIP-2 format)\nconst chain = await sdk.chainId();       // 'solana-devnet'\nconst cluster = sdk.getCluster();         // 'devnet' | 'mainnet-beta' | 'testnet'\n\n// Program IDs for all registries\nconst programs = sdk.getProgramIds();\n// programs.identityRegistry   -> PublicKey\n// programs.reputationRegistry -> PublicKey\n// programs.validationRegistry -> PublicKey\n\n// Registry addresses as strings (parity with agent0-ts)\nconst regs = sdk.registries();\n// { IDENTITY: 'base58...', REPUTATION: 'base58...', VALIDATION: 'base58...' }\n\n// RPC info\nconst rpcUrl = sdk.getRpcUrl();\nconst isDefaultRpc = sdk.isUsingDefaultDevnetRpc();\nconst canBulkQuery = sdk.supportsAdvancedQueries();\nconst readOnly = sdk.isReadOnly;\n\n// Base collection (single-collection architecture in v0.6.x)\nconst base = await sdk.getBaseCollection();\n\n// Advanced: access underlying clients\nconst solanaClient = sdk.getSolanaClient();\nconst feedbackMgr = sdk.getFeedbackManager();\n\n13. Tags Reference\nCategory tags (tag1)\nConstant\tString\tValue Type\tATOM Auto-Score\nTag.starred\t'starred'\t0-100\tYes\nTag.uptime\t'uptime'\tpercentage\tYes\nTag.successRate\t'successRate'\tpercentage\tYes\nTag.reachable\t'reachable'\t0 or 1\tNo\nTag.ownerVerified\t'ownerVerified'\t0 or 1\tNo\nTag.responseTime\t'responseTime'\tms\tNo\nTag.blocktimeFreshness\t'blocktimeFreshness'\tblocks\tNo\nTag.revenues\t'revenues'\tcurrency\tNo\nTag.tradingYield\t'tradingYield'\tpercentage\tNo\nPeriod tags (tag2)\nConstant\tString\nTag.day\t'day'\nTag.week\t'week'\nTag.month\t'month'\nTag.year\t'year'\nx402 tags (tag1) - Client -> Agent\nConstant\tString\nTag.x402ResourceDelivered\t'x402-resource-delivered'\nTag.x402DeliveryFailed\t'x402-delivery-failed'\nTag.x402DeliveryTimeout\t'x402-delivery-timeout'\nTag.x402QualityIssue\t'x402-quality-issue'\nx402 tags (tag1) - Agent -> Client\nConstant\tString\nTag.x402GoodPayer\t'x402-good-payer'\nTag.x402PaymentFailed\t'x402-payment-failed'\nTag.x402InsufficientFunds\t'x402-insufficient-funds'\nTag.x402InvalidSignature\t'x402-invalid-signature'\nx402 network tags (tag2)\nConstant\tString\nTag.x402Evm\t'exact-evm'\nTag.x402Svm\t'exact-svm'\nTag utilities\nisKnownTag('uptime');              // true\nisKnownTag('custom-metric');       // false\ngetTagDescription('successRate');   // 'Task completion success percentage'\n\n\nCustom tags are fully supported - any string up to 32 UTF-8 bytes.\n\n14. OASF Taxonomy\n// List taxonomy slugs\nconst skills = getAllSkills();   // 136 skills\nconst domains = getAllDomains(); // 204 domains\n\n15. Hash Utilities\n// SHA-256 (async, browser-compatible via WebCrypto)\nconst hash = await SolanaSDK.computeHash('My feedback content');\nconst bufHash = await SolanaSDK.computeHash(Buffer.from(jsonData));\n// Returns: Buffer (32 bytes)\n\n// URI hash (zeros for IPFS/Arweave since CID is already content-addressable)\nconst uriHash = await SolanaSDK.computeUriHash('https://example.com/data.json');\n// -> SHA-256 of the URI string\nconst ipfsHash = await SolanaSDK.computeUriHash('ipfs://Qm...');\n// -> Buffer.alloc(32) (zeros)\n\n// Keccak-256 (synchronous, used by SEAL v1)\nimport { keccak256 } from '8004-solana';\nconst k = keccak256(Buffer.from('data'));\n\n// SHA-256 sync (CJS context only — uses require('crypto'), throws in pure ESM or browser)\nimport { sha256Sync } from '8004-solana';\nconst s = sha256Sync('data');  // Uint8Array (32 bytes)\n\n16. Value Encoding\nimport {\n  encodeReputationValue,\n  decodeToDecimalString,\n  decodeToNumber,\n} from '8004-solana';\n\n// Encode: decimal string -> { value: bigint, valueDecimals: number }\nconst encoded = encodeReputationValue('99.77');\n// { value: 9977n, valueDecimals: 2, normalized: '99.77' }\n\nconst neg = encodeReputationValue('-15.5');\n// { value: -155n, valueDecimals: 1, normalized: '-15.5' }\n\nconst raw = encodeReputationValue(9977n, 2);\n// { value: 9977n, valueDecimals: 2, normalized: '99.77' }\n\n// Decode: bigint + decimals -> string or number\ndecodeToDecimalString(9977n, 2);   // '99.77'\ndecodeToDecimalString(-155n, 1);   // '-15.5'\ndecodeToNumber(9977n, 2);          // 99.77\n\n// Limits: max 6 decimal places, clamped to i64 range\n\n17. Canonical JSON & Signing Utilities\nimport {\n  canonicalizeJson,\n  normalizeSignData,\n  createNonce,\n} from '8004-solana';\n\n// RFC 8785 canonical JSON (deterministic key ordering, no whitespace)\ncanonicalizeJson({ b: 2, a: 1 });  // '{\"a\":1,\"b\":2}'\n\n// Normalize data for signing (handles BigInt, PublicKey, Date, Buffer)\nconst normalized = normalizeSignData({\n  amount: 100n,           // -> { $bigint: '100' }\n  key: somePubkey,        // -> { $pubkey: 'base58...' }\n  when: new Date(),       // -> { $date: 'ISO...' }\n  data: Buffer.from([1]), // -> { $bytes: 'AQ==', encoding: 'base64' }\n});\n\n// Cryptographic nonce generation (base58-encoded random bytes)\nconst nonce = createNonce();     // 16 bytes default\nconst nonce32 = createNonce(32); // 32 bytes\n\n18. IPFS Operations\n// Add data\nconst jsonCid = await ipfs.addJson({ key: 'value' });\nconst rawCid = await ipfs.add('raw string data');\nconst fileCid = await ipfs.addFile('./image.png');\n\n// Add registration file (normalizes and formats)\nconst registrationCid = await ipfs.addRegistrationFile(registrationFile);\n\n// Retrieve\nconst data = await ipfs.get(jsonCid);              // raw string\nconst json = await ipfs.getJson(jsonCid);          // parsed JSON\nconst reg = await ipfs.getRegistrationFile(registrationCid); // RegistrationFile\n\n// Supports ipfs:// prefix\nconst ipfsPrefixedData = await ipfs.get('ipfs://QmAbc...');\n\n// Pin/unpin\nawait ipfs.pin(fileCid);\nawait ipfs.unpin(fileCid);\n\n// Cleanup\nawait ipfs.close();\n\n19. Server Mode (skipSend)\n\nFor browser wallets or external signing:\n\n// Get unsigned transaction\nconst assetKeypair = Keypair.generate();\nconst prepared = await sdk.registerAgent(uri, undefined, {\n  skipSend: true,\n  signer: ownerPubkey,              // required when SDK has no signer\n  assetPubkey: assetKeypair.publicKey, // required in skipSend mode\n});\n// prepared.transaction -> base64 serialized unsigned transaction\n// prepared.signer -> base58 of the required signer\n\n// For agent wallet (browser wallet flow)\nconst { message, complete } = await sdk.prepareSetAgentWallet(\n  assetPubkey,\n  walletPubkey,\n  { signer: ownerPubkey } // optional if SDK was initialized with signer\n);\nconst signature = await phantomWallet.signMessage(message);\nawait complete(signature);\n\n\nAll write methods accept { skipSend: true } in their options.\n\n20. Indexer Client (Direct Access)\nconst indexer = sdk.getIndexerClient();\n\n// Check availability\nconst available = await sdk.isIndexerAvailable();\n\n// Direct queries\nconst agents = await indexer.getAgentsByOwner('base58...');\nconst feedbacks = await indexer.getFeedbacks('base58...', { limit: 100 });\nconst leaderboard = await indexer.getLeaderboard({ minTier: 3 });\n\nWait for indexer sync after write\nawait sdk.giveFeedback(assetPubkey, feedbackParams);\n\n// Poll until indexer catches up (returns true if synced, false on timeout)\nconst synced = await sdk.waitForIndexerSync(\n  async () => {\n    const fbs = await sdk.getFeedbacksFromIndexer(assetPubkey);\n    return fbs.length >= expectedCount;\n  },\n  { timeout: 30000 }  // ms, default 30s\n);\n\n21. Error Handling\nimport {\n  IndexerError,\n  IndexerUnavailableError,\n  IndexerTimeoutError,\n  IndexerRateLimitError,\n  UnsupportedRpcError,\n  RpcNetworkError,\n} from '8004-solana';\n\ntry {\n  const agents = await sdk.getAllAgents();\n} catch (e) {\n  if (e instanceof UnsupportedRpcError) {\n    // Default RPC doesn't support getProgramAccounts\n    // Use Helius, QuickNode, or Alchemy\n  }\n  if (e instanceof IndexerUnavailableError) {\n    // Indexer is down, SDK falls back to RPC if indexerFallback=true\n  }\n  if (e instanceof IndexerRateLimitError) {\n    // Back off and retry\n  }\n}\n\nMethods requiring premium RPC\n\ngetAllAgents(), getAgentsByOwner(), getCollectionAgents(), getCollections()\n\nIndexer-backed reads (readAllFeedback(), getClients(), getLastIndex(), readResponses()) do not require premium RPC, but they do require a reachable indexer.\n\n22. Operation Costs (Solana devnet)\nOperation\tCost\tNotes\nregisterAgent()\t~0.00651 SOL\tIncludes ATOM auto-init\ngiveFeedback() (1st for agent)\t~0.00332 SOL\tCreates reputation PDA\ngiveFeedback() (subsequent)\t~0.00209 SOL\tFeedback PDA only\nsetMetadata() (1st key)\t~0.00319 SOL\tPDA rent\nsetMetadata() (update)\t~0.000005 SOL\tTX fee only\nappendResponse() (1st)\t~0.00275 SOL\tResponse + index PDAs\nappendResponse() (subsequent)\t~0.00163 SOL\tResponse PDA only\nrevokeFeedback()\t~0.000005 SOL\tTX fee only\ndeleteMetadata()\trecovers rent\tReturns lamports to owner\n23. Common Patterns\nMonitor agent health\nconst report = await sdk.isItAlive(assetPubkey);\nif (report.status !== 'live') {\n  await sdk.giveFeedback(assetPubkey, {\n    value: 0,\n    valueDecimals: 0,\n    tag1: Tag.reachable,\n    score: 0,\n    feedbackUri: `ipfs://${alertCid}`,\n  });\n}\n\nPeriodic uptime reporting\nconst uptimePercent = calculateUptime(); // your logic\nawait sdk.giveFeedback(assetPubkey, {\n  value: uptimePercent.toFixed(2),  // \"99.75\" auto-encodes\n  tag1: Tag.uptime,\n  tag2: Tag.day,\n  feedbackUri: `ipfs://${reportCid}`,\n});\n\nTrust-gated interaction\nconst tier = await sdk.getTrustTier(assetPubkey);\nif (tier < TrustTier.Silver) {\n  throw new Error('Agent trust too low for this operation');\n}\n\nx402 payment feedback (full flow)\n// 1. Build the feedback file JSON (off-chain proof of payment)\nconst feedbackFile = {\n  version: '1.0',\n  type: 'x402-feedback',\n  agent: assetPubkey.toBase58(),\n  client: clientPubkey.toBase58(),\n  endpoint: '/api/generate',\n  timestamp: new Date().toISOString(),\n  proofOfPayment: {\n    txHash: 'base58-tx-signature...',\n    fromAddress: clientPubkey.toBase58(),\n    toAddress: agentWalletPubkey.toBase58(),\n    amount: '0.001',\n    token: 'SOL',\n    chainId: await sdk.chainId(),   // 'solana-devnet'\n  },\n  settlement: {\n    success: true,\n    network: 'solana',\n    settledAt: new Date().toISOString(),\n  },\n  result: {\n    delivered: true,\n    latencyMs: 230,\n    quality: 'good',\n  },\n};\n\n// 2. Upload to IPFS\nconst feedbackCid = await ipfs.addJson(feedbackFile);\n\n// 3. Optionally compute content hash for SEAL integrity\nconst feedbackFileHash = await SolanaSDK.computeHash(\n  JSON.stringify(feedbackFile)\n);\n\n// 4. Submit on-chain feedback with proof link\nawait sdk.giveFeedback(assetPubkey, {\n  value: '100.00',\n  tag1: Tag.x402ResourceDelivered,\n  tag2: Tag.x402Svm,\n  score: 95,\n  endpoint: '/api/generate',\n  feedbackUri: `ipfs://${feedbackCid}`,\n  feedbackFileHash,  // links file content to on-chain SEAL\n});\n\n// Agent-side: report good payer\nawait sdk.giveFeedback(clientAgentPubkey, {\n  value: '1',\n  valueDecimals: 0,\n  tag1: Tag.x402GoodPayer,\n  tag2: Tag.x402Svm,\n  score: 100,\n  feedbackUri: `ipfs://${payerProofCid}`,\n});\n\nVerify before trusting indexer data\nconst integrity = await sdk.verifyIntegrity(assetPubkey);\nif (!integrity.trustworthy) {\n  console.warn(`Indexer data not trustworthy: ${integrity.status}`);\n  // Fall back to on-chain queries\n}\n\n24. Program IDs\nimport {\n  PROGRAM_ID,            // Agent Registry: 8oo48pya1SZD23ZhzoNMhxR2UGb8BRa41Su4qP9EuaWm\n  MPL_CORE_PROGRAM_ID,   // Metaplex Core: CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d\n  ATOM_ENGINE_PROGRAM_ID, // ATOM: AToM1iKaniUCuWfHd5WQy5aLgJYWMiKq78NtNJmtzSXJ\n} from '8004-solana';"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/MonteCrypto999/solana-agent-registry",
    "publisherUrl": "https://clawhub.ai/MonteCrypto999/solana-agent-registry",
    "owner": "MonteCrypto999",
    "version": "1.0.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/solana-agent-registry",
    "downloadUrl": "https://openagent3.xyz/downloads/solana-agent-registry",
    "agentUrl": "https://openagent3.xyz/skills/solana-agent-registry/agent",
    "manifestUrl": "https://openagent3.xyz/skills/solana-agent-registry/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/solana-agent-registry/agent.md"
  }
}