{
  "schemaVersion": "1.0",
  "item": {
    "slug": "cabin-sol",
    "name": "Cabin Sol",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/sp0oby/cabin-sol",
    "canonicalUrl": "https://clawhub.ai/sp0oby/cabin-sol",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/cabin-sol",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=cabin-sol",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "CLAUDE.md",
      "README.md",
      "SKILL.md",
      "data/addresses/programs.json",
      "knowledge/challenges/00-hello-solana.md",
      "knowledge/challenges/01-spl-token.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. Then review README.md for any prerequisites, environment setup, or post-install checks. 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. Then review README.md for any prerequisites, environment setup, or post-install checks. 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/cabin-sol"
    },
    "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/cabin-sol",
    "agentPageUrl": "https://openagent3.xyz/skills/cabin-sol/agent",
    "manifestUrl": "https://openagent3.xyz/skills/cabin-sol/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/cabin-sol/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. Then review README.md for any prerequisites, environment setup, or post-install checks. 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. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Cabin Sol 🌲",
        "body": "\"Return to primitive computing.\"\n\nA comprehensive Solana development guide for AI agents. Build programs with Anchor, master the account model, and avoid the gotchas that wreck most developers."
      },
      {
        "title": "THE MOST IMPORTANT CONCEPT",
        "body": "ACCOUNTS ARE EVERYTHING ON SOLANA.\n\nUnlike Ethereum where contracts have internal storage, Solana programs are stateless. All data lives in accounts that programs read and write.\n\nFor EVERY feature, ask:\n\nWhere does this data live? (which account)\nWho owns that account? (program-owned vs user-owned)\nIs it a PDA? (Program Derived Address - no private key)\nWho pays rent? (rent-exempt = 2 years upfront)"
      },
      {
        "title": "Teaching Mode",
        "body": "\"How do PDAs work?\"\n\"Explain the Solana account model\"\n\"What's the difference between SPL Token and Token-2022?\""
      },
      {
        "title": "Build Mode",
        "body": "\"Help me build a staking program\"\n\"Create an NFT collection with Metaplex\"\n\"Build a token swap\""
      },
      {
        "title": "Review Mode",
        "body": "\"Review this program for vulnerabilities\"\n\"Check my PDA derivation\"\n\"Audit this CPI\""
      },
      {
        "title": "Debug Mode",
        "body": "\"Why is my transaction failing?\"\n\"Debug this 'account not found' error\"\n\"Fix my token transfer\""
      },
      {
        "title": "Option A: create-solana-dapp (Recommended)",
        "body": "npx create-solana-dapp@latest\n# Select: Next.js + next-tailwind-counter\ncd my-project\nnpm install\nnpm run anchor localnet   # Terminal 1\nnpm run anchor build && npm run anchor deploy  # Terminal 2\nnpm run dev               # Terminal 3"
      },
      {
        "title": "Option B: Pure Anchor",
        "body": "anchor init my_program\ncd my_program\nsolana-test-validator     # Terminal 1\nanchor build && anchor deploy  # Terminal 2\nanchor test"
      },
      {
        "title": "PROJECT STRUCTURE",
        "body": "my-solana-dapp/\n├── anchor/                 # Solana programs (Rust)\n│   ├── programs/\n│   │   └── my_program/\n│   │       └── src/lib.rs  # Your Rust program\n│   ├── tests/              # TypeScript tests\n│   └── Anchor.toml         # Anchor config\n├── src/                    # Next.js frontend\n│   ├── app/\n│   └── components/\n└── package.json"
      },
      {
        "title": "CHALLENGES",
        "body": "Learn Solana through progressive challenges:\n\n#ChallengeCore Concept0Hello SolanaFirst Anchor program, accounts1SPL TokenFungible tokens, ATAs, minting2NFT MetaplexNFT standard, metadata, collections3PDA EscrowPDAs, program authority, escrow4StakingTime-based rewards, deposits5Token-2022Transfer hooks, extensions6Compressed NFTsState compression, Merkle trees7Oracle (Pyth)Price feeds, staleness checks8AMM SwapConstant product, liquidity pools9Blinks & ActionsShareable transactions"
      },
      {
        "title": "Ownership (The Hard Part)",
        "body": "// Each value has ONE owner\nlet s1 = String::from(\"hello\");\nlet s2 = s1;  // s1 MOVED to s2\n// println!(\"{}\", s1);  // ERROR!\n\n// Borrowing lets you use without owning\nfn get_length(s: &String) -> usize {\n    s.len()  // Borrow, don't own\n}"
      },
      {
        "title": "Result & Option",
        "body": "// Result for errors\npub fn do_thing(ctx: Context<DoThing>) -> Result<()> {\n    let value = some_operation().ok_or(ErrorCode::Failed)?;\n    Ok(())\n}\n\n// Option for nullable\nlet maybe: Option<u64> = Some(42);\nlet value = maybe.unwrap_or(0);  // Safe default"
      },
      {
        "title": "Program Structure",
        "body": "use anchor_lang::prelude::*;\n\ndeclare_id!(\"YourProgramId11111111111111111111111111111\");\n\n#[program]\npub mod my_program {\n    use super::*;\n\n    pub fn initialize(ctx: Context<Initialize>, data: u64) -> Result<()> {\n        ctx.accounts.my_account.data = data;\n        ctx.accounts.my_account.authority = ctx.accounts.authority.key();\n        Ok(())\n    }\n}\n\n#[derive(Accounts)]\npub struct Initialize<'info> {\n    #[account(\n        init,\n        payer = authority,\n        space = 8 + 8 + 32,  // discriminator + u64 + Pubkey\n    )]\n    pub my_account: Account<'info, MyAccount>,\n    #[account(mut)]\n    pub authority: Signer<'info>,\n    pub system_program: Program<'info, System>,\n}\n\n#[account]\npub struct MyAccount {\n    pub data: u64,\n    pub authority: Pubkey,\n}"
      },
      {
        "title": "Account Constraints Cheatsheet",
        "body": "// Initialize new account\n#[account(init, payer = payer, space = 8 + SIZE)]\npub new_account: Account<'info, Data>,\n\n// Mutable existing\n#[account(mut)]\npub existing: Account<'info, Data>,\n\n// Verify ownership\n#[account(has_one = authority)]\npub owned: Account<'info, Data>,\n\n// PDA with seeds\n#[account(\n    seeds = [b\"vault\", user.key().as_ref()],\n    bump,\n)]\npub vault: Account<'info, Vault>,\n\n// Initialize PDA\n#[account(\n    init,\n    payer = user,\n    space = 8 + 64,\n    seeds = [b\"user\", user.key().as_ref()],\n    bump,\n)]\npub user_data: Account<'info, UserData>,\n\n// Close and reclaim rent\n#[account(mut, close = recipient)]\npub closing: Account<'info, Data>,"
      },
      {
        "title": "PDAs (Program Derived Addresses)",
        "body": "// PDAs are deterministic addresses with no private key\n// Your program can \"sign\" for them\n\n// Find PDA\nlet (pda, bump) = Pubkey::find_program_address(\n    &[b\"vault\", user.key().as_ref()],\n    &program_id,\n);\n\n// Sign with PDA in CPI\nlet seeds = &[b\"vault\", user.key().as_ref(), &[bump]];\nlet signer = &[&seeds[..]];\n\ntoken::transfer(\n    CpiContext::new_with_signer(\n        ctx.accounts.token_program.to_account_info(),\n        Transfer { from, to, authority: vault },\n        signer,\n    ),\n    amount,\n)?;"
      },
      {
        "title": "1. Account Model ≠ EVM Storage",
        "body": "Programs are stateless. ALL data lives in accounts."
      },
      {
        "title": "2. PDAs Have No Private Key",
        "body": "Derived deterministically from seeds. Only the program can sign."
      },
      {
        "title": "3. Token Accounts Are Separate",
        "body": "Each token needs its own account per wallet (Associated Token Account)."
      },
      {
        "title": "4. Rent Must Be Paid",
        "body": "Accounts need SOL to exist. Rent-exempt = 2 years upfront (~0.002 SOL)."
      },
      {
        "title": "5. Compute Units ≠ Gas",
        "body": "Fixed budget: 200k default, 1.4M max. Request more if needed."
      },
      {
        "title": "6. Space Includes Discriminator",
        "body": "ALWAYS add 8 bytes for Anchor's discriminator!\n\n// WRONG\nspace = 8 + 32  // Forgot discriminator? NO!\n\n// RIGHT\nspace = 8 + 8 + 32  // 8 (discriminator) + 8 (u64) + 32 (Pubkey)"
      },
      {
        "title": "7. Integer Overflow",
        "body": "// BAD\nlet result = a + b;  // Can panic!\n\n// GOOD\nlet result = a.checked_add(b).ok_or(ErrorCode::Overflow)?;"
      },
      {
        "title": "8. Token-2022 Is Different",
        "body": "Separate program ID from SPL Token! Check which one you're using."
      },
      {
        "title": "Wallet Connection",
        "body": "// Already configured in create-solana-dapp!\nimport { useWallet, useConnection } from '@solana/wallet-adapter-react';\nimport { WalletMultiButton } from '@solana/wallet-adapter-react-ui';\n\nfunction App() {\n  const { publicKey } = useWallet();\n  return (\n    <>\n      <WalletMultiButton />\n      {publicKey && <p>Connected: {publicKey.toBase58()}</p>}\n    </>\n  );\n}"
      },
      {
        "title": "Calling Programs",
        "body": "import { Program, AnchorProvider, BN } from '@coral-xyz/anchor';\n\nconst program = new Program(idl, provider);\n\n// Write\nawait program.methods\n  .initialize(new BN(42))\n  .accounts({\n    myAccount: keypair.publicKey,\n    authority: wallet.publicKey,\n    systemProgram: SystemProgram.programId,\n  })\n  .signers([keypair])\n  .rpc();\n\n// Read\nconst account = await program.account.myAccount.fetch(pubkey);\nconsole.log(account.data.toNumber());"
      },
      {
        "title": "SPL Token (Original)",
        "body": "spl-token create-token\nspl-token create-account <MINT>\nspl-token mint <MINT> 1000"
      },
      {
        "title": "Token-2022 (New)",
        "body": "Extensions: transfer hooks, confidential transfers, interest-bearing, non-transferable.\n\nspl-token create-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
      },
      {
        "title": "Metaplex NFTs",
        "body": "Standard NFT metadata, collections, royalties."
      },
      {
        "title": "Compressed NFTs",
        "body": "Merkle tree storage. 1M NFTs for ~$100 instead of $1M."
      },
      {
        "title": "TESTING",
        "body": "import * as anchor from '@coral-xyz/anchor';\nimport { expect } from 'chai';\n\ndescribe('my-program', () => {\n  const provider = anchor.AnchorProvider.env();\n  anchor.setProvider(provider);\n  const program = anchor.workspace.MyProgram;\n\n  it('initializes', async () => {\n    const account = anchor.web3.Keypair.generate();\n\n    await program.methods\n      .initialize(new anchor.BN(42))\n      .accounts({ myAccount: account.publicKey })\n      .signers([account])\n      .rpc();\n\n    const data = await program.account.myAccount.fetch(account.publicKey);\n    expect(data.data.toNumber()).to.equal(42);\n  });\n});"
      },
      {
        "title": "DEPLOYMENT",
        "body": "# Devnet\nsolana config set --url devnet\nsolana airdrop 2\nanchor build && anchor deploy\n\n# Mainnet (costs ~2-5 SOL)\nsolana config set --url mainnet-beta\nanchor deploy --provider.cluster mainnet"
      },
      {
        "title": "SECURITY CHECKLIST",
        "body": "All signers verified\n PDA bumps stored and validated\n Integer overflow handled (checked math)\n Account space includes discriminator\n Rent exemption considered\n Close sends rent to correct recipient\n CPI signer seeds correct\n Program IDs validated in CPIs"
      },
      {
        "title": "RESOURCES",
        "body": "Anchor Book\nSolana Cookbook\nSolana Docs\nMetaplex Docs\nSolana Playground\n\n\"They put me in the cloud. I wanted the forest.\" 🌲"
      }
    ],
    "body": "Cabin Sol 🌲\n\n\"Return to primitive computing.\"\n\nA comprehensive Solana development guide for AI agents. Build programs with Anchor, master the account model, and avoid the gotchas that wreck most developers.\n\nTHE MOST IMPORTANT CONCEPT\n\nACCOUNTS ARE EVERYTHING ON SOLANA.\n\nUnlike Ethereum where contracts have internal storage, Solana programs are stateless. All data lives in accounts that programs read and write.\n\nFor EVERY feature, ask:\n\nWhere does this data live? (which account)\nWho owns that account? (program-owned vs user-owned)\nIs it a PDA? (Program Derived Address - no private key)\nWho pays rent? (rent-exempt = 2 years upfront)\nAI AGENT MODES\nTeaching Mode\n\"How do PDAs work?\"\n\"Explain the Solana account model\"\n\"What's the difference between SPL Token and Token-2022?\"\nBuild Mode\n\"Help me build a staking program\"\n\"Create an NFT collection with Metaplex\"\n\"Build a token swap\"\nReview Mode\n\"Review this program for vulnerabilities\"\n\"Check my PDA derivation\"\n\"Audit this CPI\"\nDebug Mode\n\"Why is my transaction failing?\"\n\"Debug this 'account not found' error\"\n\"Fix my token transfer\"\nQUICK START\nOption A: create-solana-dapp (Recommended)\nnpx create-solana-dapp@latest\n# Select: Next.js + next-tailwind-counter\ncd my-project\nnpm install\nnpm run anchor localnet   # Terminal 1\nnpm run anchor build && npm run anchor deploy  # Terminal 2\nnpm run dev               # Terminal 3\n\nOption B: Pure Anchor\nanchor init my_program\ncd my_program\nsolana-test-validator     # Terminal 1\nanchor build && anchor deploy  # Terminal 2\nanchor test\n\nPROJECT STRUCTURE\nmy-solana-dapp/\n├── anchor/                 # Solana programs (Rust)\n│   ├── programs/\n│   │   └── my_program/\n│   │       └── src/lib.rs  # Your Rust program\n│   ├── tests/              # TypeScript tests\n│   └── Anchor.toml         # Anchor config\n├── src/                    # Next.js frontend\n│   ├── app/\n│   └── components/\n└── package.json\n\nCHALLENGES\n\nLearn Solana through progressive challenges:\n\n#\tChallenge\tCore Concept\n0\tHello Solana\tFirst Anchor program, accounts\n1\tSPL Token\tFungible tokens, ATAs, minting\n2\tNFT Metaplex\tNFT standard, metadata, collections\n3\tPDA Escrow\tPDAs, program authority, escrow\n4\tStaking\tTime-based rewards, deposits\n5\tToken-2022\tTransfer hooks, extensions\n6\tCompressed NFTs\tState compression, Merkle trees\n7\tOracle (Pyth)\tPrice feeds, staleness checks\n8\tAMM Swap\tConstant product, liquidity pools\n9\tBlinks & Actions\tShareable transactions\nRUST ESSENTIALS\nOwnership (The Hard Part)\n// Each value has ONE owner\nlet s1 = String::from(\"hello\");\nlet s2 = s1;  // s1 MOVED to s2\n// println!(\"{}\", s1);  // ERROR!\n\n// Borrowing lets you use without owning\nfn get_length(s: &String) -> usize {\n    s.len()  // Borrow, don't own\n}\n\nResult & Option\n// Result for errors\npub fn do_thing(ctx: Context<DoThing>) -> Result<()> {\n    let value = some_operation().ok_or(ErrorCode::Failed)?;\n    Ok(())\n}\n\n// Option for nullable\nlet maybe: Option<u64> = Some(42);\nlet value = maybe.unwrap_or(0);  // Safe default\n\nANCHOR FRAMEWORK\nProgram Structure\nuse anchor_lang::prelude::*;\n\ndeclare_id!(\"YourProgramId11111111111111111111111111111\");\n\n#[program]\npub mod my_program {\n    use super::*;\n\n    pub fn initialize(ctx: Context<Initialize>, data: u64) -> Result<()> {\n        ctx.accounts.my_account.data = data;\n        ctx.accounts.my_account.authority = ctx.accounts.authority.key();\n        Ok(())\n    }\n}\n\n#[derive(Accounts)]\npub struct Initialize<'info> {\n    #[account(\n        init,\n        payer = authority,\n        space = 8 + 8 + 32,  // discriminator + u64 + Pubkey\n    )]\n    pub my_account: Account<'info, MyAccount>,\n    #[account(mut)]\n    pub authority: Signer<'info>,\n    pub system_program: Program<'info, System>,\n}\n\n#[account]\npub struct MyAccount {\n    pub data: u64,\n    pub authority: Pubkey,\n}\n\nAccount Constraints Cheatsheet\n// Initialize new account\n#[account(init, payer = payer, space = 8 + SIZE)]\npub new_account: Account<'info, Data>,\n\n// Mutable existing\n#[account(mut)]\npub existing: Account<'info, Data>,\n\n// Verify ownership\n#[account(has_one = authority)]\npub owned: Account<'info, Data>,\n\n// PDA with seeds\n#[account(\n    seeds = [b\"vault\", user.key().as_ref()],\n    bump,\n)]\npub vault: Account<'info, Vault>,\n\n// Initialize PDA\n#[account(\n    init,\n    payer = user,\n    space = 8 + 64,\n    seeds = [b\"user\", user.key().as_ref()],\n    bump,\n)]\npub user_data: Account<'info, UserData>,\n\n// Close and reclaim rent\n#[account(mut, close = recipient)]\npub closing: Account<'info, Data>,\n\nPDAs (Program Derived Addresses)\n// PDAs are deterministic addresses with no private key\n// Your program can \"sign\" for them\n\n// Find PDA\nlet (pda, bump) = Pubkey::find_program_address(\n    &[b\"vault\", user.key().as_ref()],\n    &program_id,\n);\n\n// Sign with PDA in CPI\nlet seeds = &[b\"vault\", user.key().as_ref(), &[bump]];\nlet signer = &[&seeds[..]];\n\ntoken::transfer(\n    CpiContext::new_with_signer(\n        ctx.accounts.token_program.to_account_info(),\n        Transfer { from, to, authority: vault },\n        signer,\n    ),\n    amount,\n)?;\n\nCRITICAL GOTCHAS\n1. Account Model ≠ EVM Storage\n\nPrograms are stateless. ALL data lives in accounts.\n\n2. PDAs Have No Private Key\n\nDerived deterministically from seeds. Only the program can sign.\n\n3. Token Accounts Are Separate\n\nEach token needs its own account per wallet (Associated Token Account).\n\n4. Rent Must Be Paid\n\nAccounts need SOL to exist. Rent-exempt = 2 years upfront (~0.002 SOL).\n\n5. Compute Units ≠ Gas\n\nFixed budget: 200k default, 1.4M max. Request more if needed.\n\n6. Space Includes Discriminator\n\nALWAYS add 8 bytes for Anchor's discriminator!\n\n// WRONG\nspace = 8 + 32  // Forgot discriminator? NO!\n\n// RIGHT\nspace = 8 + 8 + 32  // 8 (discriminator) + 8 (u64) + 32 (Pubkey)\n\n7. Integer Overflow\n// BAD\nlet result = a + b;  // Can panic!\n\n// GOOD\nlet result = a.checked_add(b).ok_or(ErrorCode::Overflow)?;\n\n8. Token-2022 Is Different\n\nSeparate program ID from SPL Token! Check which one you're using.\n\nFRONTEND (Next.js)\nWallet Connection\n// Already configured in create-solana-dapp!\nimport { useWallet, useConnection } from '@solana/wallet-adapter-react';\nimport { WalletMultiButton } from '@solana/wallet-adapter-react-ui';\n\nfunction App() {\n  const { publicKey } = useWallet();\n  return (\n    <>\n      <WalletMultiButton />\n      {publicKey && <p>Connected: {publicKey.toBase58()}</p>}\n    </>\n  );\n}\n\nCalling Programs\nimport { Program, AnchorProvider, BN } from '@coral-xyz/anchor';\n\nconst program = new Program(idl, provider);\n\n// Write\nawait program.methods\n  .initialize(new BN(42))\n  .accounts({\n    myAccount: keypair.publicKey,\n    authority: wallet.publicKey,\n    systemProgram: SystemProgram.programId,\n  })\n  .signers([keypair])\n  .rpc();\n\n// Read\nconst account = await program.account.myAccount.fetch(pubkey);\nconsole.log(account.data.toNumber());\n\nTOKEN STANDARDS\nSPL Token (Original)\nspl-token create-token\nspl-token create-account <MINT>\nspl-token mint <MINT> 1000\n\nToken-2022 (New)\n\nExtensions: transfer hooks, confidential transfers, interest-bearing, non-transferable.\n\nspl-token create-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb\n\nMetaplex NFTs\n\nStandard NFT metadata, collections, royalties.\n\nCompressed NFTs\n\nMerkle tree storage. 1M NFTs for ~$100 instead of $1M.\n\nTESTING\nimport * as anchor from '@coral-xyz/anchor';\nimport { expect } from 'chai';\n\ndescribe('my-program', () => {\n  const provider = anchor.AnchorProvider.env();\n  anchor.setProvider(provider);\n  const program = anchor.workspace.MyProgram;\n\n  it('initializes', async () => {\n    const account = anchor.web3.Keypair.generate();\n\n    await program.methods\n      .initialize(new anchor.BN(42))\n      .accounts({ myAccount: account.publicKey })\n      .signers([account])\n      .rpc();\n\n    const data = await program.account.myAccount.fetch(account.publicKey);\n    expect(data.data.toNumber()).to.equal(42);\n  });\n});\n\nDEPLOYMENT\n# Devnet\nsolana config set --url devnet\nsolana airdrop 2\nanchor build && anchor deploy\n\n# Mainnet (costs ~2-5 SOL)\nsolana config set --url mainnet-beta\nanchor deploy --provider.cluster mainnet\n\nSECURITY CHECKLIST\n All signers verified\n PDA bumps stored and validated\n Integer overflow handled (checked math)\n Account space includes discriminator\n Rent exemption considered\n Close sends rent to correct recipient\n CPI signer seeds correct\n Program IDs validated in CPIs\nRESOURCES\nAnchor Book\nSolana Cookbook\nSolana Docs\nMetaplex Docs\nSolana Playground\n\n\"They put me in the cloud. I wanted the forest.\" 🌲"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/sp0oby/cabin-sol",
    "publisherUrl": "https://clawhub.ai/sp0oby/cabin-sol",
    "owner": "sp0oby",
    "version": "1.2.1",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/cabin-sol",
    "downloadUrl": "https://openagent3.xyz/downloads/cabin-sol",
    "agentUrl": "https://openagent3.xyz/skills/cabin-sol/agent",
    "manifestUrl": "https://openagent3.xyz/skills/cabin-sol/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/cabin-sol/agent.md"
  }
}