{"author":{"address":"0x99DD70Cb7d9F8B85EDeE2a454E56478Cd0b0EaEF","user":"https://learnblockchain.cn/people/23775"},"content":{"body":"1. **模块简介**\r\n\r\n`animal_crossing::wild_NFT` 是一个 Sui Move 模块，旨在创建、管理和操作与濒危动物相关的 NFT 系统。通过引入 `wild_coin` 和 `SUI`，模块结合金融激励机制实现了 NFT 的铸造、购买、遗弃及空投等功能。\r\n\r\n2. **主要结构体及功能**\r\n\r\n2.1 **主要结构体**\r\n\r\n以下是主要结构体的介绍以及相关功能的补充代码示例。\r\n\r\n2.1.1 **Animals**\r\n\r\n存储珍稀动物信息的结构体，每种动物包含唯一的 UID 和对应的详细信息表。\r\n\r\n```rust\r\npublic struct Animals has key, store {\r\n    id: UID,\r\n    animal_infos: Table\u003cu64, AnimalInfo\u003e,\r\n}\r\n```\r\n\r\n**功能**：\r\n\r\n1. **添加动物信息（Admin 权限）**\r\n\r\n   管理员可以向 `Animals` 添加新的动物信息。\r\n\r\n   示例代码：\r\n\r\n   ```rust\r\n   public fun add_animal(\r\n       _: \u0026NFTAdminCap,\r\n       animals: \u0026mut Animals,\r\n       name: String,\r\n       species: String,\r\n       habitat: String,\r\n       status: u64,\r\n       image_url: String,\r\n       ctx: \u0026mut TxContext,\r\n   ) {\r\n       let new_animal = AnimalInfo {\r\n           id: object::new(ctx),\r\n           name,\r\n           species,\r\n           habitat,\r\n           status,\r\n           image_url,\r\n       };\r\n       let key = table::length(\u0026animals.animal_infos);\r\n       table::add(\u0026mut animals.animal_infos, key, new_animal);\r\n   }\r\n   ```\r\n\r\n2. **更新动物信息（Admin 权限）**\r\n\r\n   根据给定的键更新指定的动物信息。\r\n\r\n   示例代码：\r\n\r\n   ```rust\r\n   public fun update_animal(\r\n       _: \u0026NFTAdminCap,\r\n       animals: \u0026mut Animals,\r\n       key: u64,\r\n       new_name: String,\r\n       new_status: u64,\r\n       ctx: \u0026mut TxContext,\r\n   ) {\r\n       assert!(table::contains(\u0026animals.animal_infos, key), ERR_KEY_DOES_NOT_EXIST);\r\n       let animal_info = table::borrow_mut(\u0026mut animals.animal_infos, key);\r\n       animal_info.name = new_name;\r\n       animal_info.status = new_status;\r\n   }\r\n   ```\r\n\r\n2.1.2 **AnimalNFT**\r\n\r\n每个动物对应的 NFT 结构体，记录了动物的基本信息和收养人的地址。\r\n\r\n```rust\r\npublic struct AnimalNFT has key, store {\r\n    id: UID,\r\n    name: String,\r\n    animal_id: u64,\r\n    species: String,\r\n    habitat: String,\r\n    adopted_by: address,\r\n    image_url: String,\r\n    create_time: u64,\r\n}\r\n```\r\n\r\n**功能**：\r\n\r\n1. **铸造 NFT（购买功能）**\r\n\r\n   使用特定金额的 `WILD_COIN` 购买指定动物的 NFT。\r\n\r\n   示例代码：\r\n\r\n   ```rust\r\n   public fun mint_nft(\r\n       animals: \u0026Animals,\r\n       key: u64,\r\n       inputcoin: Coin\u003cwild_coin::WILD_COIN\u003e,\r\n       recipient: address,\r\n       clock: \u0026Clock,\r\n       ctx: \u0026mut TxContext,\r\n   ) {\r\n       assert!(coin::value(\u0026inputcoin) == NFT_PRICE, ERR_NFT_PRICE_IS_EXACTLY_NFT_PRICE_WILD_COIN);\r\n       let animal_info = \u0026animals.animal_infos[key];\r\n       let new_nft = AnimalNFT {\r\n           id: object::new(ctx),\r\n           name: animal_info.name,\r\n           animal_id: key,\r\n           species: animal_info.species,\r\n           habitat: animal_info.habitat,\r\n           adopted_by: recipient,\r\n           image_url: animal_info.image_url,\r\n           create_time: clock::timestamp_ms(clock),\r\n       };\r\n       transfer::public_transfer(new_nft, recipient);\r\n   }\r\n   ```\r\n\r\n2. **放弃 NFT（销毁功能）**\r\n\r\n   用户可通过销毁 NFT 来收回一定的 `SUI` 或 `WILD_COIN`。\r\n\r\n   示例代码：\r\n\r\n   ```rust\r\n   public fun abandon_nft(\r\n       nft: AnimalNFT,\r\n       vault: \u0026mut WildVault,\r\n       ctx: \u0026mut TxContext,\r\n   ) {\r\n       let reward_coin = wild_coin::withdraw_wild_coin_from_vault(vault, NFT_PRICE, ctx);\r\n       transfer::public_transfer(reward_coin, nft.adopted_by);\r\n       object::delete(nft.id);\r\n   }\r\n   ```\r\n\r\n2.1.3 **MintRecord**\r\n\r\n记录 NFT 铸造的历史，包括每种动物的所有 NFT 数据。\r\n\r\n```rust\r\npublic struct MintRecord has key, store {\r\n    id: UID,\r\n    record: LinkedTable\u003cu64, LinkedTable\u003cID, u64\u003e\u003e, // 每种动物的 NFT 链接表\r\n    count: u64,\r\n}\r\n```\r\n\r\n**功能**：\r\n\r\n1. **记录铸造历史**\r\n\r\n   将 NFT 铸造记录加入到 `MintRecord` 中。\r\n\r\n   示例代码：\r\n\r\n   ```rust\r\n   public fun record_minting(\r\n       record: \u0026mut MintRecord,\r\n       nft_id: ID,\r\n       animal_key: u64,\r\n       clock: \u0026Clock,\r\n       ctx: \u0026mut TxContext,\r\n   ) {\r\n       if (!linked_table::contains(\u0026record.record, animal_key)) {\r\n           let mut new_nft_table = linked_table::new\u003cID, u64\u003e(ctx);\r\n           linked_table::push_back(\u0026mut new_nft_table, nft_id, clock::timestamp_ms(clock));\r\n           linked_table::push_back(\u0026mut record.record, animal_key, new_nft_table);\r\n       } else {\r\n           let nft_table = linked_table::borrow_mut(\u0026mut record.record, animal_key);\r\n           linked_table::push_back(nft_table, nft_id, clock::timestamp_ms(clock));\r\n       };\r\n       record.count = record.count + 1;\r\n   }\r\n   ```\r\n\r\n2. **移除铸造记录**\r\n\r\n   在 NFT 被放弃时，将其从记录中移除。\r\n\r\n   示例代码：\r\n\r\n   ```rust\r\n   public fun remove_mint_record(\r\n       record: \u0026mut MintRecord,\r\n       nft_id: ID,\r\n       animal_key: u64,\r\n   ) {\r\n       assert!(linked_table::contains(\u0026record.record, animal_key), ERR_KEY_DOES_NOT_EXIST);\r\n       let nft_table = linked_table::borrow_mut(\u0026mut record.record, animal_key);\r\n       linked_table::remove(nft_table, nft_id);\r\n       if (linked_table::is_empty(nft_table)) {\r\n           linked_table::remove(\u0026mut record.record, animal_key);\r\n       };\r\n       record.count = record.count - 1;\r\n   }\r\n   ```\r\n\r\n# 3. 核心逻辑：空头发放机制\r\n\r\n本节详细阐述系统核心逻辑“空头发放”的实现，包括数据收集、权重计算、分发奖励等核心步骤，结合代码示例展示具体实现。\r\n\r\n## 3.1 空头发放的流程概述\r\n1. 数据收集：从系统中获取所有相关 NFT 数据，包括其状态和持有时长。\r\n2. 权重计算：基于状态权重和时间权重，计算总权重。\r\n3. 奖励分发：按权重比例分配奖励，确保激励公平性。\r\n\r\n## 3.2 核心函数解析\r\n\r\n以下是实现“空头发放”的完整代码及其功能分解。\r\n\r\n```rust\r\npublic fun calculate_send_airdrop_distribution(\r\n    _: \u0026NFTAdminCap,             // 管理权限验证\r\n    record: \u0026MintRecord,         // 链上记录存储所有 NFT 信息\r\n    animals: \u0026Animals,           // 动物信息表\r\n    vault: \u0026mut WildVault,       // 系统资金库\r\n    clock: \u0026Clock,               // 当前时间\r\n    ctx: \u0026mut TxContext          // 交易上下文\r\n) {\r\n    let mut total_status_weight = 0u64;\r\n    let mut total_time_weight = 0u64;\r\n    let mut airdrop_table = linked_table::new\u003cID, u64\u003e(ctx);\r\n\r\n    // Step 1: 收集数据并计算总权重\r\n    let current_time = clock::timestamp_ms(clock);\r\n    let mut front_item = linked_table::front(\u0026record.record);\r\n    let mut nft_weights = linked_table::new\u003cID, Nft_weight\u003e(ctx);\r\n\r\n    while (option::is_some(front_item)) {\r\n        let key = option::borrow(front_item);\r\n        let nfts = linked_table::borrow(\u0026record.record, *key);\r\n        let animal_info = table::borrow(\u0026animals.animal_infos, *key);\r\n        let status_weight = animal_info.status;\r\n\r\n        let mut front_nft = linked_table::front(nfts);\r\n        while (option::is_some(front_nft)) {\r\n            let nft_key = option::borrow\u003cID\u003e(front_nft);\r\n            let create_time = linked_table::borrow(nfts, *nft_key);\r\n\r\n            // 计算持有时长的时间权重\r\n            let time_held = current_time - *create_time;\r\n            let time_weight = time_held / 86400000 + 1;\r\n\r\n            total_status_weight += status_weight;\r\n            total_time_weight += time_weight;\r\n\r\n            linked_table::push_back(\u0026mut nft_weights, *nft_key, Nft_weight {\r\n                status_weight,\r\n                time_weight,\r\n            });\r\n\r\n            front_nft = linked_table::next(nfts, *nft_key);\r\n        };\r\n\r\n        front_item = linked_table::next(\u0026record.record, *key);\r\n    };\r\n\r\n    assert!(total_status_weight \u003e 0, 1);\r\n    assert!(total_time_weight \u003e 0, 2);\r\n\r\n    // Step 2: 基于权重计算空头分配\r\n    let mut front_item = linked_table::front(\u0026nft_weights);\r\n    while (option::is_some(front_item)) {\r\n        let nft_id = option::borrow(front_item);\r\n        let Nft_weight { status_weight, time_weight } = linked_table::borrow(\u0026nft_weights, *nft_id);\r\n\r\n        let status_ratio = *status_weight * 1_000_000_000 / total_status_weight;\r\n        let time_ratio = *time_weight * 1_000_000_000 / total_time_weight;\r\n\r\n        // 自定义奖励分配公式\r\n        let reward = status_ratio * 8 / 10 + time_ratio * 2 / 10;\r\n        linked_table::push_back(\u0026mut airdrop_table, *nft_id, reward);\r\n\r\n        front_item = linked_table::next(\u0026nft_weights, *nft_id);\r\n    };\r\n\r\n    // Step 3: 发放空头奖励\r\n    wild_coin::distribute_airdrop(\u0026airdrop_table, vault, ctx);\r\n    linked_table::drop(airdrop_table);\r\n    linked_table::drop(nft_weights);\r\n}\r\n```\r\n\r\n## 3.3 功能分解\r\n1. 数据收集与初始化：\r\n   - 从 MintRecord 和 Animals 中提取每个 NFT 的状态信息和创建时间。\r\n   - 计算 `status_weight` 和 `time_weight`。\r\n2. 总权重计算：\r\n   - `status_weight` 根据动物的当前状态赋予不同权重。\r\n   - `time_weight` 根据 NFT 持有的天数计算，时间越长权重越高。\r\n3. 空头奖励计算：\r\n   - 通过状态权重和时间权重的比例计算每个 NFT 的奖励。\r\n   - 默认权重分配规则：状态权重占比 80%，时间权重占比 20%。\r\n4. 奖励分发与清理：\r\n   - 调用 `wild_coin::distribute_airdrop` 函数分发奖励。\r\n   - 清理分配数据表释放资源。\r\n\r\n## 3.4 技术亮点\r\n1. 动态权重计算：权重计算逻辑支持灵活扩展，可调整分配比例。\r\n2. 链表高效存储：采用 `linked_table` 实现 NFT 权重与奖励的高效存储和迭代。\r\n3. 代码模块化：逻辑清晰分层，便于未来维护和扩展。\r\n\r\n通过该设计，系统实现了一个公平、高效的空头发放机制，增强了用户参与的激励效果，为平台经济生态注入活力。\r\n\r\n\u003e **请用微信关注《HOH水分子》公众号，我们将持续分享和制作变成语言教程，让大家对编程产生化学反应。**\r\n![HOH_QR.jpg](https://img.learnblockchain.cn/attachments/2024/11/4h04Aovz6738b68758d43.jpg)","title":"（二十）学习笔记：解析 animal_crossing::wild_NFT 模块"},"history":null,"timestamp":1734013708,"version":1}