Rust NFT分片化库pallet-nft-fractionalization的使用,实现非同质化代币(NFT)拆分与流动性增强

Rust NFT分片化库pallet-nft-fractionalization的使用,实现非同质化代币(NFT)拆分与流动性增强

锁定NFT

pallet-nfts锁定一个NFT并从pallet-assets铸造可替代资产。

NFT通过设置一个名为Locked的系统级属性被锁定。这防止了NFT的进一步转移。当Locked属性被移除时,NFT将被解锁。为了统一可替代资产并解锁NFT,账户必须持有NFT被分片成的资产的全部发行量。持有较少可替代资产将不允许解锁NFT。

安装

在项目目录中运行以下Cargo命令:

cargo add pallet-nft-fractionalization

或在Cargo.toml中添加以下行:

pallet-nft-fractionalization = "24.0.0"

完整示例代码

use frame_support::{decl_module, decl_storage, decl_event, dispatch};
use frame_system::ensure_signed;
use sp_runtime::traits::StaticLookup;
use pallet_nfts::{self as nfts};
use pallet_assets::{self as assets};

pub trait Trait: nfts::Trait + assets::Trait {
    type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
}

decl_storage! {
    trait Store for Module<T: Trait> as NftFractionalization {
        /// Maps fractionalized NFT to its asset counterpart
        FractionalizedNft get(fn fractionalized_nft): map hasher(blake2_128_concat) (T::NftId, T::ClassId) => Option<T::AssetId>;
    }
}

decl_event! {
    pub enum Event<T> where 
        <T as frame_system::Trait>::AccountId,
        <T as nfts::Trait>::NftId,
        <T as nfts::Trait>::ClassId,
        <T as assets::Trait>::AssetId,
    {
        /// NFT was fractionalized into fungible tokens
        NftFractionalized(AccountId, NftId, ClassId, AssetId, u128),
        /// Fungible tokens were unified back into NFT
        NftUnified(AccountId, NftId, ClassId, AssetId),
    }
}

decl_module! {
    pub struct Module<T: Trait> for enum Call where origin: T::Origin {
        fn deposit_event() = default;

        /// Fractionalize an NFT into fungible tokens
        #[weight = 10_000]
        pub fn fractionalize(
            origin,
            nft_id: T::NftId,
            class_id极好的,让我们继续完成这个NFT分片化库的使用指南。

## 完整示例代码(续)

```rust
            origin,
            nft_id: T::NftId,
            class_id: T::ClassId,
            asset_id: T::AssetId,
            amount: u128,
        ) -> dispatch::DispatchResult {
            let sender = ensure_signed(origin)?;
            
            // 锁定NFT
            nfts::Module::<T>::set_attribute(
                &sender,
                &class_id,
                &nft_id,
                b"Locked",
                &[1u8],
            )?;
            
            // 铸造可替代代币
            assets::Module::<T>::mint(
                asset_id,
                &sender,
                amount,
            )?;
            
            // 存储映射关系
            FractionalizedNft::<T>::insert((nft_id.clone(), class_id.clone()), asset_id.clone());
            
            Self::deposit_event(RawEvent::NftFractionalized(
                sender,
                nft_id,
                class_id,
                asset_id,
                amount,
            ));
            
            Ok(())
        }

        /// 将可替代代币统一回NFT
        #[weight = 10_000]
        pub fn unify(
            origin,
            nft_id: T::NftId,
            class_id: T::ClassId,
        ) -> dispatch::DispatchResult {
            let sender = ensure_signed(origin)?;
            
            // 获取资产ID
            let asset_id = FractionalizedNft::<T>::get((nft_id.clone(), class_id.clone()))
                .ok_or("NFT not fractionalized")?;
            
            // 检查发送者是否持有全部供应量
            let total_supply = assets::Module::<T>::total_supply(asset_id);
            let sender_balance = assets::Module::<T>::balance(asset_id, &sender);
            
            ensure!(sender_balance == total_supply, "必须持有所有代币");
            
            // 销毁所有代币
            assets::Module::<T>::burn(
                asset_id,
                &sender,
                total_supply,
            )?;
            
            // 解锁NFT
            nfts::Module::<T>::clear_attribute(
                &sender,
                &class_id,
                &nft_id,
                b"Locked",
            )?;
            
            // 移除映射关系
            FractionalizedNft::<T>::remove((nft_id.clone(), class_id.clone()));
            
            Self::deposit_event(RawEvent::NftUnified(
                sender,
                nft_id,
                class_id,
                asset_id,
            ));
            
            Ok(())
        }
    }
}

代码注释说明

  1. 存储定义

    • FractionalizedNft 映射存储了NFT与其对应的可替代资产ID
  2. 事件定义

    • NftFractionalized 当NFT被分片成可替代代币时触发
    • NftUnified 当可替代代币被统一回NFT时触发
  3. 分片化逻辑

    • fractionalize 函数锁定NFT并铸造相应数量的可替代代币
    • 使用set_attribute方法设置"Locked"属性来锁定NFT
    • 使用mint方法铸造可替代代币
  4. 统一逻辑

    • unify 函数检查调用者是否持有所有分片代币
    • 如果满足条件,则销毁所有代币并解锁NFT
    • 使用clear_attribute方法移除"Locked"属性来解锁NFT

这个实现展示了如何使用pallet-nft-fractionalization库来增强NFT的流动性,通过将高价值的NFT分片化为可替代代币,使其更容易交易和部分所有权转移。


1 回复

Rust NFT分片化库pallet-nft-fractionalization使用指南

概述

pallet-nft-fractionalization是一个基于Substrate框架的Rust库,用于实现非同质化代币(NFT)的分片化功能。它允许将单个NFT拆分为多个同质化代币(FT),从而增强NFT的流动性和可交易性。

主要功能

  1. 将NFT拆分为指定数量的同质化代币
  2. 将分片化的NFT重新组合为原始NFT
  3. 管理分片化NFT的所有权和交易

使用方法

1. 添加依赖

首先需要在你的Substrate项目的runtime/Cargo.toml中添加依赖:

[dependencies]
pallet-nft-fractionalization = { git = "https://github.com/substrate-developer-hub/pallet-nft-fractionalization", branch = "main" }

2. 配置Runtime

在你的runtime中实现必要的trait并包含该pallet:

impl pallet_nft_fractionalization::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    type Currency = Balances;
    type NFTCollectionId = u32;
    type NFTId = u32;
    type FTIdentifier = u32;
    type WeightInfo = ();
}

construct_runtime!(
    pub enum Runtime where
        Block = Block,
        NodeBlock = opaque::Block,
        UncheckedExtrinsic = UncheckedExtrinsic,
    {
        // ... 其他pallet
        NftFractionalization: pallet_nft_fractionalization,
    }
);

3. 基本操作示例

分片化NFT

// 假设你有一个NFT,collection_id=1, nft_id=5
let collection_id = 1;
let nft_id = 5;
let fractions = 1000; // 拆分为1000个代币

// 调用分片化函数
NftFractionalization::fractionalize(
    RuntimeOrigin::signed(owner_account),
    collection_id,
    nft_id,
    fractions,
);

交易分片化代币

分片化后,你可以像普通FT一样交易这些代币:

// 转账50个分片化代币给另一个账户
Balances::transfer(
    RuntimeOrigin::signed(owner_account),
    recipient_account,
    50,
);

重新组合NFT

// 需要持有全部分片化代币才能重新组合
NftFractionalization::unfractionalize(
    RuntimeOrigin::signed(owner_account),
    collection_id,
    nft_id,
);

4. 查询功能

// 查询NFT是否已被分片化
let is_fractionalized = NftFractionalization::is_fractionalized(collection_id, nft_id);

// 获取分片化NFT的信息
let fractionalized_info = NftFractionalization::fractionalized_nfts(collection_id, nft_id);

高级用法

自定义分片化代币属性

你可以通过扩展Config trait来定制分片化代币的属性:

impl pallet_nft_fractionalization::Config for Runtime {
    // ... 其他配置
    type FTMetadata = Vec<u8>;
    
    fn ft_metadata(
        collection_id: Self::NFTCollectionId,
        nft_id: Self::NFTId
    ) -> Self::FTMetadata {
        format!("Fractionalized NFT {}-{}", collection_id, nft_id).into_bytes()
    }
}

与其它pallet集成

pallet-nft-fractionalization可以与其它pallet如pallet-assetspallet-uniques配合使用,构建更复杂的DeFi应用。

注意事项

  1. 分片化操作需要支付交易费用
  2. 只有NFT所有者才能进行分片化操作
  3. 重新组合时需要持有全部分片化代币
  4. 分片化代币的价值由市场决定,可能与原始NFT价值不同

通过使用pallet-nft-fractionalization,你可以为NFT市场增加流动性,使高价值NFT能够被更多投资者部分拥有和交易。

完整示例代码

//! 完整NFT分片化示例

use frame_support::{decl_module, decl_event, decl_storage, dispatch::DispatchResult};
use frame_system::ensure_signed;
use sp_runtime::traits::CheckedConversion;
use sp_std::prelude::*;

// 定义配置trait
pub trait Config: frame_system::Config {
    type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;
    type Currency: Currency<Self::AccountId>;
    type NFTCollectionId: Member + Parameter + Default + Copy;
    type NFTId: Member + Parameter + Default + Copy;
    type FTIdentifier: Member + Parameter + Default + Copy;
}

// 存储定义
decl_storage! {
    trait Store for Module<T: Config> as NftFractionalization {
        // 存储分片化NFT的信息
        pub FractionalizedNfts get(fn fractionalized_nfts):
            double_map hasher(blake2_128_concat) T::NFTCollectionId, hasher(blake2_128_concat) T::NFTId
            => Option<FractionalizedNft<T::AccountId, T::FTIdentifier>>;
    }
}

// 事件定义
decl_event!(
    pub enum Event<T> where
        AccountId = <T as frame_system::Config>::AccountId,
        NFTCollectionId = <T as Config>::NFTCollectionId,
        NFTId = <T as Config>::NFTId,
        FTIdentifier = <T as Config>::FTIdentifier,
    {
        // NFT成功分片化事件
        NftFractionalized(AccountId, NFTCollectionId, NFTId, FTIdentifier, u128),
        // NFT成功重组事件
        NftUnfractionalized(AccountId, NFTCollectionId, NFTId),
    }
);

// 模块定义
decl_module! {
    pub struct Module<T: Config> for enum Call where origin: T::Origin {
        // 初始化事件
        fn deposit_event() = default;

        // 分片化NFT函数
        #[weight = 10_000]
        pub fn fractionalize(
            origin,
            collection_id: T::NFTCollectionId,
            nft_id: T::NFTId,
            fractions: u128,
        ) -> DispatchResult {
            let owner = ensure_signed(origin)?;
            
            // 检查NFT是否已存在且未被分片化
            ensure!(!<FractionalizedNfts<T>>::contains_key(collection_id, nft_id), "NFT already fractionalized");
            
            // 创建分片化代币标识符
            let ft_id = Self::generate_ft_id(collection_id, nft_id);
            
            // 创建分片化代币
            T::Currency::mint_into(&owner, fractions.checked_into().ok_or("Overflow")?)?;
            
            // 存储分片化信息
            let fractionalized = FractionalizedNft {
                owner: owner.clone(),
                ft_id: ft_id.clone(),
                total_fractions: fractions,
            };
            <FractionalizedNfts<T>>::insert(collection_id, nft_id, fractionalized);
            
            // 触发事件
            Self::deposit_event(RawEvent::NftFractionalized(owner, collection_id, nft_id, ft_id, fractions));
            
            Ok(())
        }

        // 重组NFT函数
        #[weight = 10_000]
        pub fn unfractionalize(
            origin,
            collection_id: T::NFTCollectionId,
            nft_id: T::NFTId,
        ) -> DispatchResult {
            let owner = ensure_signed(origin)?;
            
            // 获取分片化信息
            let fractionalized = <FractionalizedNfts<T>>::get(collection_id, nft_id)
                .ok_or("NFT not fractionalized")?;
                
            // 检查调用者是否为所有者
            ensure!(fractionalized.owner == owner, "Not the owner");
            
            // 销毁所有分片化代币
            T::Currency::burn_from(&owner, fractionalized.total_fractions.checked_into().ok_or("Overflow")?)?;
            
            // 移除存储
            <FractionalizedNfts<T>>::remove(collection_id, nft_id);
            
            // 触发事件
            Self::deposit_event(RawEvent::NftUnfractionalized(owner, collection_id, nft_id));
            
            Ok(())
        }
    }
}

// 分片化NFT信息结构体
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
pub struct FractionalizedNft<AccountId, FTIdentifier> {
    pub owner: AccountId,
    pub ft_id: FTIdentifier,
    pub total_fractions: u128,
}

impl<T: Config> Module<T> {
    // 生成分片化代币标识符
    fn generate_ft_id(collection_id: T::NFTCollectionId, nft_id: T::NFTId) -> T::FTIdentifier {
        // 简单实现:将collection_id和nft_id组合作为标识符
        // 实际项目中可能需要更复杂的逻辑
        let mut encoded = Vec::new();
        collection_id.encode_to(&mut encoded);
        nft_id.encode_to(&mut encoded);
        T::FTIdentifier::decode(&mut &encoded[..]).unwrap_or_default()
    }
}

这个完整示例展示了如何实现一个基本的NFT分片化模块,包括:

  1. 存储分片化NFT的信息
  2. 实现分片化和重组功能
  3. 处理相关事件
  4. 管理分片化代币的创建和销毁

你可以根据需要扩展这个基础实现,添加更多功能如:

  • 部分重组功能
  • 分片化代币交易手续费
  • 更复杂的分片化代币标识符生成逻辑
  • 与其他pallet的集成等
回到顶部