Rust区块链NFT开发库pallet-nfts的使用,支持非同质化代币创建、管理和交易的Substrate模块
以下是基于您提供的NFTs pallet内容的完整示例demo,展示了如何使用NFTs pallet创建集合、铸造NFT、设置元数据并管理交易:
use frame_support::{parameter_types, traits::GenesisBuild};
use sp_core::H256;
use sp_runtime::{
traits::{BlakeTwo256, IdentityLookup},
BuildStorage,
};
type Block = frame_system::mocking::MockBlock<Test>;
// 配置测试环境
frame_support::construct_runtime!(
pub enum Test {
System: frame_system,
Balances: pallet_balances,
Nfts: pallet_nfts,
}
);
parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const SS58Prefix: u8 = 42;
}
impl frame_system::Config for Test {
type BaseCallFilter = frame_support::traits::Everything;
type BlockWeights = ();
type BlockLength = ();
type DbWeight = ();
type RuntimeOrigin = RuntimeOrigin;
type RuntimeCall = RuntimeCall;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
type Hashing = BlakeTwo256;
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = sp_runtime::generic::Header<u64, BlakeTwo256>;
type RuntimeEvent = RuntimeEvent;
type BlockHashCount = BlockHashCount;
type Version = ();
type PalletInfo = PalletInfo;
type AccountData = pallet_balances::AccountData<u64>;
type OnNewAccount = ();
type OnKilledAccount = ();
type SystemWeightInfo = ();
type SS58Prefix = SS58Prefix;
type OnSetCode = ();
type MaxConsumers = frame_support::traits::ConstU32<16>;
}
parameter_types! {
pub const ExistentialDeposit: u64 = 1;
pub const MaxLocks: u32 = 10;
pub const MaxReserves: u32 = 10;
}
impl pallet_balances::Config for Test {
type Balance = u64;
type DustRemoval = ();
type RuntimeEvent = RuntimeEvent;
type ExistentialDeposit = ExistentialDeposit;
type AccountStore = System;
type WeightInfo = ();
type MaxLocks = MaxLocks;
type MaxReserves = MaxReserves;
type ReserveIdentifier = [u8; 8];
type HoldIdentifier = ();
type FreezeIdentifier = ();
type MaxHolds = ();
type MaxFreezes = ();
}
parameter_types! {
pub const CollectionDeposit: u64 = 100;
pub const ItemDeposit: u64 = 1;
pub const StringLimit: u32 = 50;
pub const AttributesLimit: u32 = 10;
pub const MetadataDepositBase: u64 = 1;
pub const AttributeDepositBase: u64 = 1;
pub const DepositPerByte: u64 = 1;
}
impl pallet_nfts::Config for Test {
type RuntimeEvent = RuntimeEvent;
type CollectionId = u32;
type ItemId = u32;
type Currency = Balances;
type CreateOrigin = frame_support::traits::AsEnsureOriginWithArg<frame_system::EnsureSigned<u64>>;
type ForceOrigin = frame_system::EnsureRoot<u64>;
type CollectionDeposit = CollectionDeposit;
type ItemDeposit = ItemDeposit;
type MetadataDepositBase = MetadataDepositBase;
type AttributeDepositBase = AttributeDepositBase;
type DepositPerByte = DepositPerByte;
type StringLimit = StringLimit;
type KeyLimit = AttributesLimit;
type ValueLimit = AttributesLimit;
type WeightInfo = ();
type Locker = ();
type RuntimeHoldReason = ();
type RuntimeFreezeReason = ();
type FreezeIdentifier = ();
type MaxFreezes = ();
type MaxHolds = ();
type ItemAttributesApprovalsLimit = ();
type MaxAttributesPerCall = ();
}
// 创建测试环境
pub fn new_test_ext() -> sp_io::TestExternalities {
let mut storage = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap();
pallet_balances::GenesisConfig::<Test> {
balances: vec![(1, 1000), (2, 1000), (3, 1000), (4, 1000)],
}
.assimilate_storage(&mut storage)
.unwrap();
storage.into()
}
#[test]
fn full_nft_workflow() {
new_test_ext().execute_with(|| {
// 1. 创建集合
assert_ok!(Nfts::create(
RuntimeOrigin::signed(1), // 创建者
1, // collection_id
1, // admin
Default::default() // 配置
));
// 2. 设置集合元数据
assert_ok!(Nfts::set_collection_metadata(
RuntimeOrigin::signed(1),
1, // collection_id
b"My NFT Collection".to_vec(),
));
// 3. 铸造NFT
assert_ok!(Nfts::mint(
RuntimeOrigin::signed(1),
1, // collection_id
1, // item_id
1, // owner
Default::default() // 配置
));
// 4. 设置NFT元数据
assert_ok!(Nfts::set_metadata(
RuntimeOrigin::signed(1),
1, // collection_id
1, // item_id
b"My First NFT".to_vec(),
));
// 5. 设置NFT属性
assert_ok!(Nfts::set_attribute(
RuntimeOrigin::signed(1),
1, // collection_id
Some(1), // item_id (None表示集合属性)
b"color".to_vec(),
b"blue".to_vec(),
));
// 6. 设置价格并购买
assert_ok!(Nfts::set_price(
RuntimeOrigin::signed(1),
1, // collection_id
1, // item_id
Some(100), // price
None // 买家白名单
));
// 7. 用户2购买NFT
assert_ok!(Nfts::buy_item(
RuntimeOrigin::signed(2),
1, // collection_id
1, // item_id
100 // bid_price
));
// 验证所有权转移
assert_eq!(Nfts::owner(1, 1), Some(2));
// 8. 创建原子交换
// 先给用户3铸造一个NFT
assert_ok!(Nfts::mint(
RuntimeOrigin::signed(1),
1, // collection_id
2, // item_id
3, // owner
Default::default()
));
// 用户2创建交换报价
assert_ok!(Nfts::create_swap(
RuntimeOrigin::signed(2),
1, // offered_collection_id
1, // offered_item_id
Some(1), // desired_collection_id
Some(2), // desired_item_id
None, // price
None // deadline
));
// 用户3接受交换
assert_ok!(Nfts::claim_swap(
RuntimeOrigin::signed(3),
vec![(1, 2)], // sent_items
2, // 发送者
vec![(1, 1)], // received_items
));
// 验证交换结果
assert_eq!(Nfts::owner(1, 1), Some(3)); // NFT1现在属于用户3
assert_eq!(Nfts::owner(1, 2), Some(2)); // NFT2现在属于用户2
// 9. 销毁NFT
assert_ok!(Nfts::burn(
RuntimeOrigin::signed(3),
1, // collection_id
1 // item_id
));
// 验证NFT已销毁
assert!(!Item::<Test>::contains_key(1, 1));
});
}
这个完整示例展示了以下NFT工作流程:
- 创建NFT集合
- 设置集合元数据
- 铸造NFT
- 设置NFT元数据和属性
- 设置价格并完成购买交易
- 创建和执行原子交换
- 销毁NFT
每个步骤都包含注释说明操作的目的和参数含义。您可以根据实际需求调整或扩展这个示例。
1 回复