运行时依赖
安装命令
点击复制技能文档
Cabin Sol “返回原始计算。” 针对AI代理的综合Solana开发指南。 使用Anchor构建程序,掌握账户模型,并避免大多数开发人员遇到的陷阱。 最重要的概念 账户是Solana上的所有事物。 与以太坊不同,以太坊的合约有内部存储,Solana程序是无状态的。 所有数据都存储在程序读写的账户中。 对于每个功能,问: 这个数据存储在哪里?(哪个账户) 谁拥有这个账户?(程序所有者与用户所有者) 这是一个PDA吗?(程序派生地址 - 没有私钥) 谁支付租金?(租金豁免 = 2年预付) AI代理模式 教学模式 “PDAs如何工作?” “解释Solana账户模型” “SPL令牌和令牌-2022有什么区别?” 构建模式 “帮助我构建一个质押程序” “使用Metaplex创建一个NFT集合” “构建一个令牌交换” 审查模式 “审查这个程序的漏洞” “检查我的PDA派生” “审计这个CPI” 调试模式 “为什么我的事务失败?” “调试这个'账户未找到'错误” “修复我的令牌转移” 快速入门 选项A:create-solana-dapp(推荐) npx create-solana-dapp@latest # 选择:Next.js + next-tailwind-counter cd my-project npm install npm run anchor localnet # 终端1 npm run anchor build && npm run anchor deploy # 终端2 npm run dev # 终端3 选项B:纯Anchor anchor init my_program cd my_program solana-test-validator # 终端1 anchor build && anchor deploy # 终端2 anchor test 项目结构 my-solana-dapp/ ├── anchor/ # Solana程序(Rust) │ ├── programs/ │ │ └── my_program/ │ │ └── src/lib.rs # 您的Rust程序 │ ├── tests/ # TypeScript测试 │ └── Anchor.toml # Anchor配置 ├── src/ # Next.js前端 │ ├── app/ │ └── components/ └── package.json 挑战 通过进步挑战学习Solana: # 挑战 核心概念 0 Hello Solana 第一个Anchor程序,账户 1 SPL令牌 令牌,ATA,铸造 2 NFT Metaplex NFT标准,元数据,集合 3 PDA Escrow PDAs,程序权限,Escrow 4 质押 时间奖励,存款 5 令牌-2022 转移钩子,扩展 6 压缩NFT 状态压缩,Merkle树 7 甲骨文(Pyth) 价格提要,过时检查 8 AMM Swap 常数产品,流动池 9 Blinks & Actions 共享事务 Rust必备 所有权(难点) // 每个值只有一个所有者 let s1 = String::from("hello"); let s2 = s1; // s1移动到s2 // println!("{}", s1); // 错误! // 借用让你使用而不拥有 fn get_length(s: &String) -> usize { s.len() // 借用,不拥有 } 结果和选项 // 结果用于错误 pub fn do_thing(ctx: Context) -> Result<()> { let value = some_operation().ok_or(ErrorCode::Failed)?; Ok(()) } // 选项用于空值 let maybe: Option = Some(42); let value = maybe.unwrap_or(0); // 安全默认 Anchor框架 程序结构 use anchor_lang::prelude::; declare_id!("YourProgramId11111111111111111111111111111"); #[program] pub mod my_program { use super::; pub fn initialize(ctx: Context, data: u64) -> Result<()> { ctx.accounts.my_account.data = data; ctx.accounts.my_account.authority = ctx.accounts.authority.key(); Ok(()) } } #[derive(Accounts)] pub struct Initialize<'info> { #[account( init, payer = authority, space = 8 + 8 + 32, // 判别式 + u64 + Pubkey )] pub my_account: Account<'info, MyAccount>, #[account(mut)] pub authority: Signer<'info>, pub system_program: Program<'info, System>, } #[account] pub struct MyAccount { pub data: u64, pub authority: Pubkey, } 账户约束速查表 // 初始化新账户 #[account(init, payer = payer, space = 8 + SIZE)] pub new_account: Account<'info, Data>, // 可变现有 #[account(mut)] pub existing: Account<'info, Data>, // 验证所有权 #[account(has_one = authority)] pub owned: Account<'info, Data>, // PDA带种子 #[account( seeds = [b"vault", user.key().as_ref()], bump, )] pub vault: Account<'info, Vault>, // 初始化PDA #[account( init, payer = user, space = 8 + 64, seeds = [b"user", user.key().as_ref()], bump, )] pub user_data: Account<'info, UserData>, // 关闭并回收租金 #[account(mut, close = recipient)] pub closing: Account<'info, Data>, PDAs(程序派生地址) // PDAs是确定性地址,没有私钥 // 您的程序可以“签名”它们 // 查找PDA let (pda, bump) = Pubkey::find_program_address( &[b"vault", user.key().as_ref()], &program_id, ); // 使用PDA在CPI中签名 let seeds = &[b"vault", user.key().as_ref(), &[bump]]; let signer = &[&seeds[..]]; token::transfer( CpiContext::new_with_signer( ctx.accounts.token_program.to_account_info(), Transfer { from, to, authority: vau