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(())
}
}
}
代码注释说明
-
存储定义:
FractionalizedNft
映射存储了NFT与其对应的可替代资产ID
-
事件定义:
NftFractionalized
当NFT被分片成可替代代币时触发NftUnified
当可替代代币被统一回NFT时触发
-
分片化逻辑:
fractionalize
函数锁定NFT并铸造相应数量的可替代代币- 使用
set_attribute
方法设置"Locked"属性来锁定NFT - 使用
mint
方法铸造可替代代币
-
统一逻辑:
unify
函数检查调用者是否持有所有分片代币- 如果满足条件,则销毁所有代币并解锁NFT
- 使用
clear_attribute
方法移除"Locked"属性来解锁NFT
这个实现展示了如何使用pallet-nft-fractionalization
库来增强NFT的流动性,通过将高价值的NFT分片化为可替代代币,使其更容易交易和部分所有权转移。
Rust NFT分片化库pallet-nft-fractionalization使用指南
概述
pallet-nft-fractionalization
是一个基于Substrate框架的Rust库,用于实现非同质化代币(NFT)的分片化功能。它允许将单个NFT拆分为多个同质化代币(FT),从而增强NFT的流动性和可交易性。
主要功能
- 将NFT拆分为指定数量的同质化代币
- 将分片化的NFT重新组合为原始NFT
- 管理分片化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-assets
或pallet-uniques
配合使用,构建更复杂的DeFi应用。
注意事项
- 分片化操作需要支付交易费用
- 只有NFT所有者才能进行分片化操作
- 重新组合时需要持有全部分片化代币
- 分片化代币的价值由市场决定,可能与原始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分片化模块,包括:
- 存储分片化NFT的信息
- 实现分片化和重组功能
- 处理相关事件
- 管理分片化代币的创建和销毁
你可以根据需要扩展这个基础实现,添加更多功能如:
- 部分重组功能
- 分片化代币交易手续费
- 更复杂的分片化代币标识符生成逻辑
- 与其他pallet的集成等