Rust区块链NFT管理库pallet-uniques的使用,Substrate框架中创建和管理独特数字资产的插件库

Uniques Module

一个简单、安全的模块,用于处理非同质化资产。

概述

Uniques模块提供了非同质化代币(NFT)的管理功能,包括:

  • 集合创建
  • 代币铸造
  • 代币转移
  • 代币交易方法
  • 属性管理
  • 代币销毁

要在你的运行时中使用它,你需要实现uniques::Config

支持的调度函数记录在uniques::Call枚举中。

术语

  • 集合创建:创建新集合
  • 代币铸造:在集合中创建新代币的行为
  • 代币转移:将代币从一个账户发送到另一个账户的行为
  • 代币销毁:销毁代币的行为
  • 非同质化代币(NFT):每个单位具有独特特征的代币。这样的代币只有一个实例存在,并且只有一个拥有账户。

目标

Substrate中的Uniques模块旨在实现以下功能:

  • 允许账户无许可地创建NFT集合
  • 允许指定(许可)账户在集合中铸造和销毁独特代币
  • 无许可地在账户之间转移代币
  • 允许指定(许可)账户冻结和解冻集合中的独特代币或整个集合
  • 允许代币所有者将转移代币的能力委托给指定的第三方

接口

无许可调度函数

  • create:通过放置押金创建新集合
  • transfer:将代币转移给新所有者
  • redeposit:更新代币的押金金额,可能释放资金
  • approve_transfer:指定可以授权转移的委托
  • cancel_approval:撤销之前approve_transfer的效果

许可调度函数

  • destroy:销毁集合
  • mint:在集合中铸造新代币
  • burn:销毁集合中的代币
  • freeze:防止单个代币被转移
  • thaw:撤销之前freeze的效果
  • freeze_collection:防止集合中的所有代币被转移
  • thaw_collection:撤销之前freeze_collection的效果
  • transfer_ownership:更改集合的所有者,转移所有相关押金
  • set_team:更改集合的许可账户

元数据(许可)调度函数

  • set_attribute:设置代币或集合的属性
  • clear_attribute:移除代币或集合的属性
  • set_metadata:设置代币的通用元数据
  • clear_metadata:移除代币的通用元数据
  • set_collection_metadata:设置集合的通用元数据
  • clear_collection_metadata:移除集合的通用元数据

强制(即治理)调度函数

  • force_create:创建新集合
  • force_asset_status:更改集合的基本特征

相关模块

  • System
  • Support
  • Assets

许可证:Apache-2.0

完整示例代码

以下是内容中提供的示例代码:

// 在runtime/src/lib.rs中添加pallet-uniques

use frame_support::traits::{Currency, ReservableCurrency};
use sp_runtime::traits::StaticLookup;

// 配置pallet-uniques
impl pallet_uniques::Config for Runtime {
    type Event = Event;
    type CollectionId = u32;
    type ItemId = u32;
    type Currency = Balances;  // 使用Balances作为货币类型
    type ForceOrigin = frame_system::EnsureRoot<AccountId>;
    type CreateOrigin = frame_system::EnsureSigned<AccountId>;
    type Locker = ();
    type WeightInfo = ();
}

// 示例调用代码
// 创建集合
let collection_id = 1;
let call = pallet_uniques::Call::<Runtime>::create {
    collection: collection_id,
    admin: account_id,
};
let origin = Origin::signed(account_id);
call.dispatch(origin)?;

// 铸造NFT
let item_id = 1;
let call = pallet_uniques::Call::<Runtime>::mint {
    collection: collection_id,
    item: item_id,
    owner: recipient_account_id,
};
let origin = Origin::signed(account_id);  // 需要是集合管理员
call.dispatch(origin)?;

// 转移NFT
let call = pallet_uniques::Call::<Runtime>::transfer {
    collection: collection_id,
    item: item_id,
    dest: new_owner_account_id,
};
let origin = Origin::signed(current_owner_account_id);
call.dispatch(origin)?;

// 设置元数据
let metadata = b"Unique Artwork #1".to_vec();
let call = pallet_uniques::Call::<Runtime>::set_metadata {
    collection: collection_id,
    item: item_id,
    data: metadata.clone(),
};
let origin = Origin::signed(account_id);  // 需要是集合管理员
call.dispatch(origin)?;

安装命令:

cargo add pallet-uniques

或者在Cargo.toml中添加:

pallet-uniques = "41.0.0"

扩展完整示例

以下是一个更完整的NFT管理示例:

// runtime/src/lib.rs
use frame_support::{parameter_types, traits::Everything};
use sp_runtime::traits::ConstU32;

parameter_types! {
    pub const CollectionDeposit: Balance = 100 * UNITS;  // 集合创建押金
    pub const ItemDeposit: Balance = 10 * UNITS;         // 代币创建押金
    pub const MetadataDepositBase: Balance = 10 * UNITS; // 元数据基础押金
    pub const AttributeDepositBase: Balance = 10 * UNITS;// 属性基础押金
}

impl pallet_uniques::Config for Runtime {
    type Event = Event;
    type CollectionId = u32;  // 集合ID类型
    type ItemId = u32;        // 代币ID类型
    type Currency = Balances; // 使用的货币类型
    type ForceOrigin = frame_system::EnsureRoot<AccountId>;
    type CreateOrigin = frame_system::EnsureSigned<AccountId>;
    type Locker = ();
    type CollectionDeposit = CollectionDeposit;
    type ItemDeposit = ItemDeposit;
    type MetadataDepositBase = MetadataDepositBase;
    type AttributeDepositBase = AttributeDepositBase;
    type DepositPerByte = ConstU32<1>;  // 每字节押金
    type StringLimit = ConstU32<256>;   // 字符串长度限制
    type KeyLimit = ConstU32<64>;       // 键长度限制
    type ValueLimit = ConstU32<64>;      // 值长度限制
    type WeightInfo = pallet_uniques::weights::SubstrateWeight<Runtime>;
    type RemoveItemsLimit = ConstU32<1000>;
    type CreateOrigin = EnsureSigned<AccountId>;
    type Features = PalletFeatures;
}

// 创建一个完整的NFT生命周期示例
fn nft_lifecycle_example() -> DispatchResult {
    let alice = 1;
    let bob = 2;
    let collection_id = 1;
    let item_id = 1;
    
    // 1. 创建集合
    Uniques::create(
        RuntimeOrigin::signed(alice),
        collection_id,
        alice  // 设置alice为集合管理员
    )?;
    
    // 2. 设置集合元数据
    Uniques::set_collection_metadata(
        RuntimeOrigin::signed(alice),
        collection_id,
        b"My Awesome Collection".to_vec(),
        false
    )?;
    
    // 3. 铸造NFT
    Uniques::mint(
        RuntimeOrigin::signed(alice),
        collection_id,
        item_id,
        alice  // 初始拥有者为alice
    )?;
    
    // 4. 设置NFT元数据
    Uniques::set_metadata(
        RuntimeOrigin::signed(alice),
        collection_id,
        item_id,
        b"Unique Artwork #1".to_vec(),
        false
    )?;
    
    // 5. 转移NFT给bob
    Uniques::transfer(
        RuntimeOrigin::signed(alice),
        collection_id,
        item_id,
        bob
    )?;
    
    // 6. bob授权alice可以转移此NFT
    Uniques::approve_transfer(
        RuntimeOrigin::signed(bob),
        collection_id,
        item_id,
        alice
    )?;
    
    // 7. alice使用授权转移NFT给自己
    Uniques::transfer(
        RuntimeOrigin::signed(alice),
        collection_id,
        item_id,
        alice
    )?;
    
    // 8. 销毁NFT
    Uniques::burn(
        RuntimeOrigin::signed(alice),
        collection_id,
        item_id
    )?;
    
    // 9. 销毁集合
    Uniques::destroy(
        RuntimeOrigin::signed(alice),
        collection_id,
        DestroyWitness {
            items: 0,
            item_metadatas: 1,
            attributes: 0
        }
    )?;
    
    Ok(())
}

这个完整示例展示了NFT的完整生命周期:

  1. 创建集合
  2. 设置集合元数据
  3. 铸造NFT
  4. 设置NFT元数据
  5. 转移NFT
  6. 授权转移
  7. 使用授权转移
  8. 销毁NFT
  9. 销毁集合

1 回复

Rust区块链NFT管理库pallet-uniques的使用指南

完整示例代码

下面是一个完整的pallet-uniques使用示例,展示了如何创建NFT集合、铸造NFT、设置元数据和转移所有权:

// runtime/src/lib.rs
// 1. 在runtime中集成pallet-uniques
impl pallet_uniques::Config for Runtime {
    type Event = Event;
    type CollectionId = u32;
    type ItemId = u32;
    type Currency = Balances;
    type CreateOrigin = frame_system::EnsureRoot<AccountId>;
    type ForceOrigin = frame_system::EnsureRoot<AccountId>;
    type Locker = ();
    type WeightInfo = ();
}

construct_runtime!(
    pub enum Runtime {
        // ... 其他pallet
        Uniques: pallet_uniques::{Pallet, Call, Storage, Event<T>},
    }
);

// 示例代码 - 在链上操作NFT
fn main() {
    // 初始化Substrate客户端等代码...
    
    // 2. 创建NFT集合
    let collection_id = 1;
    let admin = alice_account_id();
    let create_call = pallet_uniques::Call::create {
        collection: collection_id,
        admin: admin.clone(),
    };
    submit_extrinsic(create_call);
    
    // 3. 在集合中创建NFT
    let item_id = 1;
    let owner = bob_account_id();
    let mint_call = pallet_uniques::Call::mint {
        collection: collection_id,
        item: item_id,
        owner: owner.clone(),
    };
    submit_extrinsic(mint_call);
    
    // 4. 设置NFT元数据
    let metadata = b"https://example.com/nft/1.json".to_vec();
    let metadata_call = pallet_uniques::Call::set_metadata {
        collection: collection_id,
        item: item_id,
        data: metadata,
        is_frozen: false,
    };
    submit_extrinsic(metadata_call);
    
    // 5. 转移NFT所有权
    let new_owner = charlie_account_id();
    let transfer_call = pallet_uniques::Call::transfer {
        collection: collection_id,
        item: item_id,
        dest: new_owner,
    };
    submit_extrinsic(transfer_call);
    
    // 高级功能示例
    // 1. 批量创建NFT
    for i in 2..=10 {
        let mint_call = pallet_uniques::Call::mint {
            collection: collection_id,
            item: i,
            owner: owner.clone(),
        };
        submit_extrinsic(mint_call);
    }
    
    // 2. 设置集合属性
    let attributes = b"{\"description\":\"Premium Art Collection\"}".to_vec();
    let collection_metadata_call = pallet_uniques::Call::set_collection_metadata {
        collection: collection_id,
        data: attributes,
        is_frozen: false,
    };
    submit_extrinsic(collection_metadata_call);
    
    // 3. 冻结NFT
    let freeze_call = pallet_uniques::Call::freeze {
        collection: collection_id,
        item: item_id,
    };
    submit_extrinsic(freeze_call);
}

// 辅助函数 - 提交交易到链上
fn submit_extrinsic(call: pallet_uniques::Call<Runtime>) {
    // 实际实现会使用Substrate客户端API提交交易
    unimplemented!()
}

// 辅助函数 - 查询NFT信息
fn query_nft_info(collection_id: u32, item_id: u32) {
    // 1. 查询集合所有者
    let collection_owner = Uniques::collection_owner(collection_id);
    println!("Collection owner: {:?}", collection_owner);
    
    // 2. 查询NFT所有者
    let item_owner = Uniques::owner(collection_id, item_id);
    println!("NFT owner: {:?}", item_owner);
    
    // 3. 查询NFT元数据
    let item_metadata = Uniques::item_metadata(collection_id, item_id);
    println!("NFT metadata: {:?}", item_metadata);
    
    // 4. 查询集合元数据
    let collection_metadata = Uniques::collection_metadata(collection_id);
    println!("Collection metadata: {:?}", collection_metadata);
}

代码说明

  1. runtime集成:首先在Substrate runtime中配置和集成pallet-uniques
  2. NFT集合创建:使用create方法创建新的NFT集合
  3. NFT铸造:使用mint方法在集合中创建单个NFT
  4. 元数据设置:使用set_metadata为NFT设置链上元数据
  5. 所有权转移:使用transfer方法转移NFT所有权

高级功能实现

  1. 批量操作:通过循环批量创建多个NFT
  2. 集合元数据:为整个集合设置描述性元数据
  3. NFT冻结:冻结NFT防止进一步修改

查询功能

代码中包含了查询NFT信息的示例函数,可以查询:

  • 集合所有者
  • NFT当前所有者
  • NFT元数据
  • 集合元数据

注意事项

  1. 实际使用时需要替换示例中的账户ID为真实账户
  2. 提交交易需要完整的Substrate客户端实现
  3. 生产环境应考虑错误处理和交易费用
  4. 元数据大小应符合链上存储限制

这个完整示例演示了pallet-uniques从集成到使用的完整流程,可以作为开发NFT功能的起点。

回到顶部