💸 使用CPI构建支付系统 - 让评论变成金矿!
🎪 欢迎来到代币经济的核心!
热身结束了,朋友们!🔥 上节课我们建好了代币工厂,现在是时候让它开足马力运转了!想象一下:
- 📝 写影评 = 💰 获得10个代币
- 💬 发评论 = 🪙 获得5个代币
- 🚀 用户活跃 = 💎 财富积累
这就像是Play-to-Earn遇见了社交媒体!每个互动都有价值!
🎯 今日任务: 在评论和留言功能中集成代币铸造,让用户的每个贡献都能获得奖励!
🏗️ 系统架构总览
🎨 代币流程图
┌─────────────────────────────────────────┐
│ 💰 代币奖励系统 │
├─────────────────────────────────────────┤
│ │
│ 用户操作 奖励 │
│ ───────── ───── │
│ 📝 发布影评 ──→ 🪙 10个代币 │
│ 💬 发表评论 ──→ 🪙 5个代币 │
│ 🔄 更新影评 ──→ 🪙 2个代币(未来) │
│ │
│ 流程: │
│ 1. 用户提交内容 ✍️ │
│ 2. 程序验证 ✅ │
│ 3. 调用Token程序 📞 │
│ 4. 铸造代币到用户钱包 💰 │
│ │
└─────────────────────────────────────────┘
📝 Step 1: 升级影评功能
🎯 更新add_movie_review函数
首先,让我们给影评功能加入代币超能力!打开 processor.rs
:
// 🎬 在 add_movie_review 函数中
pub fn add_movie_review(
program_id: &Pubkey,
accounts: &[AccountInfo],
title: String,
rating: u8,
description: String,
) -> ProgramResult {
msg!("🎬 添加电影评论...");
msg!("📝 标题: {}", title);
msg!("⭐ 评分: {}", rating);
msg!("💭 描述: {}", description);
// 📋 解析账户列表 - 注意新增的账户!
let account_info_iter = &mut accounts.iter();
// 👤 原有账户
let initializer = next_account_info(account_info_iter)?;
let pda_account = next_account_info(account_info_iter)?;
let pda_counter = next_account_info(account_info_iter)?;
// 🆕 新增的代币相关账户!
let token_mint = next_account_info(account_info_iter)?; // 🪙 代币铸造账户
let mint_auth = next_account_info(account_info_iter)?; // 🔑 铸造权限
let user_ata = next_account_info(account_info_iter)?; // 💳 用户代币钱包
// ⚙️ 系统账户
let system_program = next_account_info(account_info_iter)?;
let token_program = next_account_info(account_info_iter)?; // 🎯 Token程序
msg!("✅ 账户解析完成!");
// ... 原有的验证逻辑 ...
}
🔐 添加账户验证
💡 黄金法则: 永远不要相信用户输入!验证一切!
// 🔍 验证所有代币相关账户
msg!("🔐 开始验证代币账户...");
// 🎯 Step 1: 派生预期的PDA地址
let (mint_pda, _mint_bump) = Pubkey::find_program_address(
&[b"token_mint"], // 🌱 铸造账户种子
program_id
);
let (mint_auth_pda, mint_auth_bump) = Pubkey::find_program_address(
&[b"token_auth"], // 🌱 权限账户种子
program_id
);
// ✅ Step 2: 验证代币铸造账户
if *token_mint.key != mint_pda {
msg!("❌ 错误:代币铸造账户不匹配!");
msg!(" 期望: {}", mint_pda);
msg!(" 实际: {}", token_mint.key);
return Err(ReviewError::IncorrectAccountError.into());
}
// ✅ Step 3: 验证铸造权限账户
if *mint_auth.key != mint_auth_pda {
msg!("❌ 错误:铸造权限不匹配!");
return Err(ReviewError::InvalidPDA.into());
}
// ✅ Step 4: 验证用户的关联代币账户(ATA)
// get_associated_token_address 计算用户应该拥有的代币账户地址
let expected_ata = get_associated_token_address(
initializer.key, // 用户地址
token_mint.key // 代币类型
);
if *user_ata.key != expected_ata {
msg!("❌ 错误:用户代币账户不正确!");
msg!(" 期望: {}", expected_ata);
msg!(" 实际: {}", user_ata.key);
return Err(ReviewError::IncorrectAccountError.into());
}
// ✅ Step 5: 验证Token程序
if *token_program.key != TOKEN_PROGRAM_ID {
msg!("❌ 错误:Token程序ID不正确!");
return Err(ReviewError::IncorrectAccountError.into());
}
msg!("✅ 所有账户验证通过!");
💰 实现代币铸造
在函数末尾,Ok(())
之前添加:
// 🎉 铸造奖励代币!
msg!("💰 准备铸造10个代币给用户...");
msg!(" 用户: {}", initializer.key);
msg!(" 代币账户: {}", user_ata.key);
// 🪄 使用CPI调用Token程序的mint_to指令
invoke_signed(
// 📜 指令:铸造代币
&spl_token::instruction::mint_to(
token_program.key, // Token程序ID
token_mint.key, // 从哪个mint铸造
user_ata.key, // 铸造到哪个账户
mint_auth.key, // 谁有权限铸造
&[], // 额外签名者(无)
10 * LAMPORTS_PER_SOL, // 💰 数量:10个代币
)?,
// 📦 涉及的账户
&[
token_mint.clone(), // Mint账户
user_ata.clone(), // 目标账户
mint_auth.clone(), // 权限账户
],
// 🔑 PDA签名种子 - 让程序代表PDA签名!
&[&[b"token_auth", &[mint_auth_bump]]],
)?;
msg!("🎊 成功铸造10个代币!");
msg!("💎 用户因发布影评获得奖励!");
Ok(())
📦 更新导入
在文件顶部更新导入:
// 🆕 添加 mint_to 导入
use spl_token::{
instruction::{initialize_mint, mint_to}, // 添加了mint_to!
ID as TOKEN_PROGRAM_ID
};
💬 Step 2: 升级评论功能
🎯 更新add_comment函数
现在让我们给评论功能也加上代币奖励!代码结构类似,但奖励数量不同:
// 💬 在 add_comment 函数中
pub fn add_comment(
program_id: &Pubkey,
accounts: &[AccountInfo],
comment: String,
) -> ProgramResult {
msg!("💬 添加评论...");
msg!("📝 内容: {}", comment);
// 📋 解析账户列表
let account_info_iter = &mut accounts.iter();
// 👤 基础账户
let commenter = next_account_info(account_info_iter)?;
let pda_review = next_account_info(account_info_iter)?;
let pda_counter = next_account_info(account_info_iter)?;
let pda_comment = next_account_info(account_info_iter)?;
// 🆕 代币相关账户
let token_mint = next_account_info(account_info_iter)?;
let mint_auth = next_account_info(account_info_iter)?;
let user_ata = next_account_info(account_info_iter)?;
// ⚙️ 程序账户
let system_program = next_account_info(account_info_iter)?;
let token_program = next_account_info(account_info_iter)?;
// ... 原有的评论创建逻辑 ...
// 🔐 验证代币账户(与影评相同的验证逻辑)
msg!("🔐 验证代币账户...");
// 派生PDA
let (mint_pda, _mint_bump) = Pubkey::find_program_address(
&[b"token_mint"],
program_id
);
let (mint_auth_pda, mint_auth_bump) = Pubkey::find_program_address(
&[b"token_auth"],
program_id
);
// 执行验证
if *token_mint.key != mint_pda {
msg!("❌ 代币铸造账户错误");
return Err(ReviewError::IncorrectAccountError.into());
}
if *mint_auth.key != mint_auth_pda {
msg!("❌ 铸造权限错误");
return Err(ReviewError::InvalidPDA.into());
}
// 验证用户ATA
if *user_ata.key != get_associated_token_address(
commenter.key,
token_mint.key
) {
msg!("❌ 用户代币账户错误");
return Err(ReviewError::IncorrectAccountError.into());
}
if *token_program.key != TOKEN_PROGRAM_ID {
msg!("❌ Token程序错误");
return Err(ReviewError::IncorrectAccountError.into());
}
// 💰 铸造评论奖励 - 5个代币!
msg!("💰 铸造5个代币作为评论奖励...");
invoke_signed(
// 📜 铸造指令
&spl_token::instruction::mint_to(
token_program.key,
token_mint.key,
user_ata.key,
mint_auth.key,
&[],
5 * LAMPORTS_PER_SOL, // 💰 5个代币的奖励
)?,
// 📦 账户列表
&[
token_mint.clone(),
user_ata.clone(),
mint_auth.clone()
],
// 🔑 PDA签名种子
&[&[b"token_auth", &[mint_auth_bump]]],
)?;
msg!("🎊 成功奖励5个代币给评论者!");
Ok(()) // ⚠️ 注意:不要重复Ok(())
}
⚠️ 常见错误: 确保函数末尾只有一个
Ok(())
!
🧪 测试你的代币系统
🔨 Step 1: 构建和部署
# 🏗️ 构建程序
cargo build-sbf
# 🚀 部署到本地网络
solana program deploy target/deploy/your_program.so
# 💡 提示:如果余额不足
solana airdrop 2
🎮 Step 2: 初始化Mint
# 📥 获取测试客户端
git clone https://github.com/buildspace/solana-movie-token-client
cd solana-movie-token-client
npm install
配置客户端:
// 📝 更新 index.ts
const PROGRAM_ID = "你的程序ID";
// 🌐 第67行 - 使用本地网络
const connection = new web3.Connection("http://localhost:8899");
运行初始化:
# 🚀 初始化代币铸造
npm start
# 🎉 你应该看到:
# "Token mint initialized!"
🎨 Step 3: 使用前端测试
# 📥 克隆前端
git clone https://github.com/buildspace/solana-movie-frontend/
cd solana-movie-frontend
# 🎯 切换到正确的分支
git checkout solution-add-tokens
# 📦 安装依赖
npm install
配置前端:
- 📝 更新程序ID
- 🌐 设置本地网络连接
- 👻 Phantom钱包切换到localhost
- 💰 确保有测试SOL
测试流程:
# 🚀 启动前端
npm run dev
# 🎯 测试步骤:
# 1. 发布一个影评 → 获得10个代币 💰
# 2. 发表一条评论 → 获得5个代币 🪙
# 3. 检查Phantom钱包 → 看到你的代币! 🎉
💡 实用技巧与最佳实践
🎯 技巧1:代币经济设计
// 💰 创建灵活的奖励系统
pub const REVIEW_REWARD: u64 = 10 * LAMPORTS_PER_SOL;
pub const COMMENT_REWARD: u64 = 5 * LAMPORTS_PER_SOL;
pub const UPDATE_REWARD: u64 = 2 * LAMPORTS_PER_SOL;
// 🎮 根据用户等级调整奖励
fn calculate_reward(user_level: u8, base_reward: u64) -> u64 {
match user_level {
1 => base_reward,
2 => base_reward * 15 / 10, // 1.5倍
3 => base_reward * 2, // 2倍
_ => base_reward,
}
}
🎯 技巧2:防止滥用
// ⏰ 添加时间限制
pub fn can_mint_reward(last_action_time: i64) -> bool {
let current_time = Clock::get()?.unix_timestamp;
let time_elapsed = current_time - last_action_time;
// 每小时只能获得一次奖励
time_elapsed >= 3600
}
// 📊 添加每日限额
pub struct UserRewardTracker {
pub daily_minted: u64,
pub last_reset: i64,
pub daily_limit: u64,
}
🎯 技巧3:错误处理优化
// 🛡️ 创建辅助函数简化验证
fn verify_token_accounts(
token_mint: &AccountInfo,
mint_auth: &AccountInfo,
user_ata: &AccountInfo,
token_program: &AccountInfo,
program_id: &Pubkey,
user: &Pubkey,
) -> ProgramResult {
// 批量验证所有账户
let (mint_pda, _) = Pubkey::find_program_address(
&[b"token_mint"],
program_id
);
if *token_mint.key != mint_pda {
return Err(ReviewError::IncorrectAccountError.into());
}
// ... 其他验证 ...
Ok(())
}
🏆 挑战任务
🎯 基础挑战:学生介绍奖励
为学生介绍程序添加代币奖励:
- 🎓 自我介绍 = 20个代币
- 💬 回复他人 = 3个代币
- 👍 点赞(新功能)= 1个代币
🎯 进阶挑战:构建完整的代币经济
创建一个更复杂的系统:
// 🎮 多层次奖励系统
pub enum ActionType {
CreateContent, // 基础奖励
QualityContent, // 高质量内容额外奖励
DailyActive, // 每日活跃奖励
Milestone, // 里程碑奖励
}
// 💎 VIP系统
pub struct VipStatus {
pub level: u8,
pub multiplier: f32,
pub special_perks: Vec<Perk>,
}
// 🏪 代币消费
pub enum TokenUse {
UnlockFeature, // 解锁功能
PurchaseNFT, // 购买NFT
Governance, // 治理投票
}
🔗 参考资源
🎓 知识总结
📚 你掌握的技能
┌─────────────────────────────────────┐
│ 🏆 成就解锁 │
├─────────────────────────────────────┤
│ ✅ 实现代币奖励系统 │
│ ✅ 掌握mint_to指令 │
│ ✅ 管理关联代币账户(ATA) │
│ ✅ 使用invoke_signed进行CPI │
│ ✅ 构建完整的代币经济 │
└─────────────────────────────────────┘
🔮 未来展望
有了代币系统,你可以:
- 🏪 创建市场和交易系统
- 🗳️ 实现DAO治理
- 🎮 构建GameFi应用
- 💎 创建会员和VIP系统
🚀 总结
恭喜!🎉 你已经成功构建了一个完整的代币奖励系统!现在你的应用不仅仅是Web3的,更是一个真正的代币经济体!
💭 思考: 代币不仅是奖励,更是构建社区和激励的强大工具。你会如何设计你的代币经济?
准备好创建下一个DeFi独角兽了吗?让代币飞起来吧! 🚀💰🌟