difftreelog
Merge pull request #6 from usetech-llc/feature/white_list_nft_62-64
in: master
Feature/white list nft 62 64
4 files changed
README.mddiffbeforeafterboth--- a/README.md
+++ b/README.md
@@ -142,6 +142,12 @@
"enable_println": "bool",
"max_subject_len": "u32"
},
+ "AccessMode": {
+ "_enum": [
+ "Normal",
+ "WhiteList"
+ ]
+ },
"CollectionMode": {
"_enum": {
"Invalid": null,
@@ -181,12 +187,13 @@
"CollectionType": {
"Owner": "AccountId",
"Mode": "CollectionMode",
- "Access": "u8",
+ "Access": "AccessMode",
"DecimalPoints": "u32",
"Name": "Vec<u16>",
"Description": "Vec<u16>",
"TokenPrefix": "Vec<u8>",
"CustomDataSize": "u32",
+ "MintMode": "bool",
"OffchainSchema": "Vec<u8>",
"Sponsor": "AccountId",
"UnconfirmedSponsor": "AccountId"
@@ -196,4 +203,5 @@
"LookupSource": "AccountId",
"Weight": "u64"
}
+
```
\ No newline at end of file
pallets/nft/src/lib.rsdiffbeforeafterboth--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -97,6 +97,7 @@
pub description: Vec<u16>, // 256 include null escape char
pub token_prefix: Vec<u8>, // 16 include null escape char
pub custom_data_size: u32,
+ pub mint_mode: bool,
pub offchain_schema: Vec<u8>,
pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender
pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship
@@ -178,9 +179,6 @@
pub NftItemList get(fn nft_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;
pub FungibleItemList get(fn fungible_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;
pub ReFungibleItemList get(fn refungible_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;
-
- // Active vesting list
- // pub VestingList get(fn vesting): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => VestingItem<T::AccountId, T::Moment>;
/// Index list
pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;
@@ -209,7 +207,7 @@
fn on_initialize(now: T::BlockNumber) -> Weight {
- if ChainVersion::get() == 0
+ if ChainVersion::get() < 2
{
let value = NextCollectionID::get();
CreatedCollectionCount::put(value);
@@ -224,11 +222,11 @@
// @param customDataSz size of custom data in each collection item
// returns collection ID
#[weight = 0]
- pub fn create_collection( origin,
- collection_name: Vec<u16>,
- collection_description: Vec<u16>,
- token_prefix: Vec<u8>,
- mode: CollectionMode) -> DispatchResult {
+ pub fn create_collection(origin,
+ collection_name: Vec<u16>,
+ collection_description: Vec<u16>,
+ token_prefix: Vec<u8>,
+ mode: CollectionMode) -> DispatchResult {
// Anyone can create a collection
let who = ensure_signed(origin)?;
@@ -271,6 +269,7 @@
owner: who.clone(),
name: name,
mode: mode.clone(),
+ mint_mode: false,
access: AccessMode::Normal,
description: description,
decimal_points: decimal_points,
@@ -309,6 +308,73 @@
}
#[weight = 0]
+ pub fn add_to_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{
+
+ let sender = ensure_signed(origin)?;
+ Self::check_owner_or_admin_permissions(collection_id, sender)?;
+
+ let mut white_list_collection: Vec<T::AccountId>;
+ if <WhiteList<T>>::contains_key(collection_id) {
+ white_list_collection = <WhiteList<T>>::get(collection_id);
+ if !white_list_collection.contains(&address.clone())
+ {
+ white_list_collection.push(address.clone());
+ }
+ }
+ else {
+ white_list_collection = Vec::new();
+ white_list_collection.push(address.clone());
+ }
+
+ <WhiteList<T>>::insert(collection_id, white_list_collection);
+ Ok(())
+ }
+
+ #[weight = 0]
+ pub fn remove_from_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{
+
+ let sender = ensure_signed(origin)?;
+ Self::check_owner_or_admin_permissions(collection_id, sender)?;
+
+ if <WhiteList<T>>::contains_key(collection_id) {
+ let mut white_list_collection = <WhiteList<T>>::get(collection_id);
+ if white_list_collection.contains(&address.clone())
+ {
+ white_list_collection.retain(|i| *i != address.clone());
+ <WhiteList<T>>::insert(collection_id, white_list_collection);
+ }
+ }
+
+ Ok(())
+ }
+
+ #[weight = 0]
+ pub fn set_public_access_mode(origin, collection_id: u64, mode: AccessMode) -> DispatchResult
+ {
+ let sender = ensure_signed(origin)?;
+
+ Self::check_owner_permissions(collection_id, sender)?;
+ let mut target_collection = <Collection<T>>::get(collection_id);
+ target_collection.access = mode;
+ <Collection<T>>::insert(collection_id, target_collection);
+
+ Ok(())
+ }
+
+ #[weight = 0]
+ pub fn set_mint_permission(origin, collection_id: u64, mint_permission: bool) -> DispatchResult
+ {
+ let sender = ensure_signed(origin)?;
+
+ Self::check_owner_permissions(collection_id, sender)?;
+ let mut target_collection = <Collection<T>>::get(collection_id);
+ target_collection.mint_mode = mint_permission;
+ <Collection<T>>::insert(collection_id, target_collection);
+
+ Ok(())
+ }
+
+ #[weight = 0]
pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {
let sender = ensure_signed(origin)?;
@@ -405,9 +471,14 @@
pub fn create_item(origin, collection_id: u64, properties: Vec<u8>, owner: T::AccountId) -> DispatchResult {
let sender = ensure_signed(origin)?;
+ Self::collection_exists(collection_id)?;
let target_collection = <Collection<T>>::get(collection_id);
- Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;
+ if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {
+ ensure!(target_collection.mint_mode == true, "Collection is not in mint mode");
+ Self::check_white_list(collection_id, owner.clone())?;
+ }
+
match target_collection.mode
{
CollectionMode::NFT(_) => {
@@ -469,10 +540,13 @@
pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {
let sender = ensure_signed(origin)?;
+ Self::collection_exists(collection_id)?;
let item_owner = Self::is_item_owner(sender.clone(), collection_id, item_id);
if !item_owner
{
- Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;
+ if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {
+ Self::check_white_list(collection_id, sender.clone())?;
+ }
}
let target_collection = <Collection<T>>::get(collection_id);
@@ -494,11 +568,10 @@
pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {
let sender = ensure_signed(origin)?;
- ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id), "Only item owner can call transfer method");
-
+ Self::check_white_list(collection_id, sender.clone())?;
+ Self::check_white_list(collection_id, recipient.clone())?;
let target_collection = <Collection<T>>::get(collection_id);
- // TODO: implement other modes
match target_collection.mode
{
CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,
@@ -518,7 +591,10 @@
// amount param stub
let amount = 100000000;
- ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id), "Only item owner can call transfer method");
+ let item_owner = Self::is_item_owner(sender.clone(), collection_id, item_id);
+ if !item_owner {
+ Self::check_white_list(collection_id, approved.clone())?;
+ }
let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));
if list_exists {
@@ -545,22 +621,21 @@
let sender = ensure_signed(origin)?;
let approved_list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone()));
- if approved_list_exists
- {
- let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));
- let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());
- ensure!(opt_item.is_some(), "No approve found");
- ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");
- // remove approve
- let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))
- .into_iter().filter(|i| i.approved != sender.clone()).collect();
- <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);
- }
- else
- {
- Self::check_owner_or_admin_permissions(collection_id, sender)?;
- }
+ ensure!(approved_list_exists, "Only approved addresses can call this method");
+
+ Self::check_white_list(collection_id, from.clone())?;
+ Self::check_white_list(collection_id, recipient.clone())?;
+
+ let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));
+ let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());
+ ensure!(opt_item.is_some(), "No approve found");
+ ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");
+
+ // remove approve
+ let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))
+ .into_iter().filter(|i| i.approved != sender.clone()).collect();
+ <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);
let target_collection = <Collection<T>>::get(collection_id);
@@ -675,11 +750,7 @@
Ok(())
}
- fn burn_refungible_item(
- collection_id: u64,
- item_id: u64,
- owner: T::AccountId,
- ) -> DispatchResult {
+ fn burn_refungible_item(collection_id: u64, item_id: u64, owner: T::AccountId) -> DispatchResult {
ensure!(
<ReFungibleItemList<T>>::contains_key(collection_id, item_id),
"Item does not exists"
@@ -770,25 +841,27 @@
Ok(())
}
- fn check_owner_or_admin_permissions(
- collection_id: u64,
- subject: T::AccountId,
- ) -> DispatchResult {
- Self::collection_exists(collection_id)?;
+ fn is_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> bool {
let target_collection = <Collection<T>>::get(collection_id);
- let is_owner = subject == target_collection.owner;
-
- let no_perm_mes = "You do not have permissions to modify this collection";
+ let mut result: bool = subject == target_collection.owner;
let exists = <AdminList<T>>::contains_key(collection_id);
- if !is_owner {
- ensure!(exists, no_perm_mes);
- ensure!(
- <AdminList<T>>::get(collection_id).contains(&subject),
- no_perm_mes
- );
+ if !result & exists {
+ if <AdminList<T>>::get(collection_id).contains(&subject) {
+ result = true
+ }
}
+
+ result
+ }
+
+ fn check_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult {
+
+ Self::collection_exists(collection_id)?;
+ let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());
+
+ ensure!(result, "You do not have permissions to modify this collection");
Ok(())
}
@@ -812,6 +885,16 @@
}
}
+ fn check_white_list(collection_id: u64, address: T::AccountId) -> DispatchResult {
+
+ let mes = "Address is not in white list";
+ ensure!(<WhiteList<T>>::contains_key(collection_id), mes);
+ let wl = <WhiteList<T>>::get(collection_id);
+ ensure!(wl.contains(&address.clone()), mes);
+
+ Ok(())
+ }
+
fn transfer_fungible(
collection_id: u64,
item_id: u64,
@@ -819,6 +902,12 @@
owner: T::AccountId,
new_owner: T::AccountId,
) -> DispatchResult {
+
+ ensure!(
+ <FungibleItemList<T>>::contains_key(collection_id, item_id),
+ "Item not exists"
+ );
+
let full_item = <FungibleItemList<T>>::get(collection_id, item_id);
let amount = full_item.value;
@@ -903,6 +992,12 @@
owner: T::AccountId,
new_owner: T::AccountId,
) -> DispatchResult {
+
+ ensure!(
+ <ReFungibleItemList<T>>::contains_key(collection_id, item_id),
+ "Item not exists"
+ );
+
let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);
let item = full_item
.owner
@@ -983,6 +1078,12 @@
sender: T::AccountId,
new_owner: T::AccountId,
) -> DispatchResult {
+
+ ensure!(
+ <NftItemList<T>>::contains_key(collection_id, item_id),
+ "Item not exists"
+ );
+
let mut item = <NftItemList<T>>::get(collection_id, item_id);
ensure!(
pallets/nft/src/tests.rsdiffbeforeafterboth1// Tests to be written here2use crate::mock::*;3use crate::{ApprovePermissions, CollectionMode, AccessMode, Ownership};4use frame_support::{assert_noop, assert_ok};56#[test]7fn create_nft_item() {8 new_test_ext().execute_with(|| {9 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();10 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();11 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();12 let mode: CollectionMode = CollectionMode::NFT(2000);1314 let origin1 = Origin::signed(1);15 assert_ok!(TemplateModule::create_collection(16 origin1.clone(),17 col_name1.clone(),18 col_desc1.clone(),19 token_prefix1.clone(),20 mode21 ));22 assert_eq!(TemplateModule::collection(1).owner, 1);2324 assert_ok!(TemplateModule::create_item(25 origin1.clone(),26 1,27 [1, 2, 3].to_vec(),28 129 ));30 assert_eq!(TemplateModule::nft_item_id(1, 1).data, [1, 2, 3].to_vec());31 });32}3334#[test]35fn create_refungible_item() {36 new_test_ext().execute_with(|| {37 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();38 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();39 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();40 let mode: CollectionMode = CollectionMode::ReFungible(2000, 3);4142 let origin1 = Origin::signed(1);43 assert_ok!(TemplateModule::create_collection(44 origin1.clone(),45 col_name1.clone(),46 col_desc1.clone(),47 token_prefix1.clone(),48 mode49 ));50 assert_eq!(TemplateModule::collection(1).owner, 1);5152 assert_ok!(TemplateModule::create_item(53 origin1.clone(),54 1,55 [1, 2, 3].to_vec(),56 157 ));58 assert_eq!(59 TemplateModule::refungible_item_id(1, 1).data,60 [1, 2, 3].to_vec()61 );62 assert_eq!(63 TemplateModule::refungible_item_id(1, 1).owner[0],64 Ownership {65 owner: 1,66 fraction: 100067 }68 );69 });70}7172#[test]73fn create_fungible_item() {74 new_test_ext().execute_with(|| {75 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();76 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();77 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();78 let mode: CollectionMode = CollectionMode::Fungible(3);7980 let origin1 = Origin::signed(1);81 assert_ok!(TemplateModule::create_collection(82 origin1.clone(),83 col_name1.clone(),84 col_desc1.clone(),85 token_prefix1.clone(),86 mode87 ));88 assert_eq!(TemplateModule::collection(1).owner, 1);8990 assert_ok!(TemplateModule::create_item(91 origin1.clone(),92 1,93 [].to_vec(),94 195 ));96 assert_eq!(TemplateModule::fungible_item_id(1, 1).owner, 1);97 assert_eq!(TemplateModule::balance_count(1, 1), 1000);98 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);99 });100}101102#[test]103fn transfer_fungible_item() {104 new_test_ext().execute_with(|| {105 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();106 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();107 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();108 let mode: CollectionMode = CollectionMode::Fungible(3);109110 let origin1 = Origin::signed(1);111 let origin2 = Origin::signed(2);112 assert_ok!(TemplateModule::create_collection(113 origin1.clone(),114 col_name1.clone(),115 col_desc1.clone(),116 token_prefix1.clone(),117 mode118 ));119 assert_eq!(TemplateModule::collection(1).owner, 1);120121 assert_ok!(TemplateModule::create_item(122 origin1.clone(),123 1,124 [].to_vec(),125 1126 ));127 assert_eq!(TemplateModule::fungible_item_id(1, 1).owner, 1);128 assert_eq!(TemplateModule::balance_count(1, 1), 1000);129 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);130131 // change owner scenario132 assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1000));133 assert_eq!(TemplateModule::fungible_item_id(1, 1).owner, 2);134 assert_eq!(TemplateModule::fungible_item_id(1, 1).value, 1000);135 assert_eq!(TemplateModule::balance_count(1, 1), 0);136 assert_eq!(TemplateModule::balance_count(1, 2), 1000);137 assert_eq!(TemplateModule::address_tokens(1, 1), []);138 assert_eq!(TemplateModule::address_tokens(1, 2), [1]);139140 // split item scenario141 assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 500));142 assert_eq!(TemplateModule::fungible_item_id(1, 1).owner, 2);143 assert_eq!(TemplateModule::fungible_item_id(1, 2).owner, 3);144 assert_eq!(TemplateModule::balance_count(1, 2), 500);145 assert_eq!(TemplateModule::balance_count(1, 3), 500);146 assert_eq!(TemplateModule::address_tokens(1, 2), [1]);147 assert_eq!(TemplateModule::address_tokens(1, 3), [2]);148149 // split item and new owner has account scenario150 assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 200));151 assert_eq!(TemplateModule::fungible_item_id(1, 1).value, 300);152 assert_eq!(TemplateModule::fungible_item_id(1, 2).value, 700);153 assert_eq!(TemplateModule::balance_count(1, 2), 300);154 assert_eq!(TemplateModule::balance_count(1, 3), 700);155 assert_eq!(TemplateModule::address_tokens(1, 2), [1]);156 assert_eq!(TemplateModule::address_tokens(1, 3), [2]);157 });158}159160#[test]161fn transfer_refungible_item() {162 new_test_ext().execute_with(|| {163 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();164 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();165 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();166 let mode: CollectionMode = CollectionMode::ReFungible(2000, 3);167168 let origin1 = Origin::signed(1);169 let origin2 = Origin::signed(2);170 assert_ok!(TemplateModule::create_collection(171 origin1.clone(),172 col_name1.clone(),173 col_desc1.clone(),174 token_prefix1.clone(),175 mode176 ));177 assert_eq!(TemplateModule::collection(1).owner, 1);178179 assert_ok!(TemplateModule::create_item(180 origin1.clone(),181 1,182 [1, 2, 3].to_vec(),183 1184 ));185 assert_eq!(186 TemplateModule::refungible_item_id(1, 1).data,187 [1, 2, 3].to_vec()188 );189 assert_eq!(190 TemplateModule::refungible_item_id(1, 1).owner[0],191 Ownership {192 owner: 1,193 fraction: 1000194 }195 );196 assert_eq!(TemplateModule::balance_count(1, 1), 1000);197 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);198199 // change owner scenario200 assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1000));201 assert_eq!(202 TemplateModule::refungible_item_id(1, 1).owner[0],203 Ownership {204 owner: 2,205 fraction: 1000206 }207 );208 assert_eq!(TemplateModule::balance_count(1, 1), 0);209 assert_eq!(TemplateModule::balance_count(1, 2), 1000);210 assert_eq!(TemplateModule::address_tokens(1, 1), []);211 assert_eq!(TemplateModule::address_tokens(1, 2), [1]);212213 // split item scenario214 assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 500));215 assert_eq!(216 TemplateModule::refungible_item_id(1, 1).owner[0],217 Ownership {218 owner: 2,219 fraction: 500220 }221 );222 assert_eq!(223 TemplateModule::refungible_item_id(1, 1).owner[1],224 Ownership {225 owner: 3,226 fraction: 500227 }228 );229 assert_eq!(TemplateModule::balance_count(1, 2), 500);230 assert_eq!(TemplateModule::balance_count(1, 3), 500);231 assert_eq!(TemplateModule::address_tokens(1, 2), [1]);232 assert_eq!(TemplateModule::address_tokens(1, 3), [1]);233234 // split item and new owner has account scenario235 assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 200));236 assert_eq!(237 TemplateModule::refungible_item_id(1, 1).owner[0],238 Ownership {239 owner: 2,240 fraction: 300241 }242 );243 assert_eq!(244 TemplateModule::refungible_item_id(1, 1).owner[1],245 Ownership {246 owner: 3,247 fraction: 700248 }249 );250 assert_eq!(TemplateModule::balance_count(1, 2), 300);251 assert_eq!(TemplateModule::balance_count(1, 3), 700);252 assert_eq!(TemplateModule::address_tokens(1, 2), [1]);253 assert_eq!(TemplateModule::address_tokens(1, 3), [1]);254 });255}256257#[test]258fn transfer_nft_item() {259 new_test_ext().execute_with(|| {260 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();261 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();262 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();263 let mode: CollectionMode = CollectionMode::NFT(2000);264265 let origin1 = Origin::signed(1);266 assert_ok!(TemplateModule::create_collection(267 origin1.clone(),268 col_name1.clone(),269 col_desc1.clone(),270 token_prefix1.clone(),271 mode272 ));273 assert_eq!(TemplateModule::collection(1).owner, 1);274275 assert_ok!(TemplateModule::create_item(276 origin1.clone(),277 1,278 [1, 2, 3].to_vec(),279 1280 ));281 assert_eq!(TemplateModule::nft_item_id(1, 1).data, [1, 2, 3].to_vec());282 assert_eq!(TemplateModule::balance_count(1, 1), 1);283 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);284285 // default scenario286 assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1000));287 assert_eq!(TemplateModule::nft_item_id(1, 1).owner, 2);288 assert_eq!(TemplateModule::balance_count(1, 1), 0);289 assert_eq!(TemplateModule::balance_count(1, 2), 1);290 assert_eq!(TemplateModule::address_tokens(1, 1), []);291 assert_eq!(TemplateModule::address_tokens(1, 2), [1]);292 });293}294295#[test]296fn nft_approve_and_transfer_from() {297 new_test_ext().execute_with(|| {298 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();299 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();300 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();301 let mode: CollectionMode = CollectionMode::NFT(2000);302303 let origin1 = Origin::signed(1);304 let origin2 = Origin::signed(2);305 assert_ok!(TemplateModule::create_collection(306 origin1.clone(),307 col_name1.clone(),308 col_desc1.clone(),309 token_prefix1.clone(),310 mode311 ));312 assert_eq!(TemplateModule::collection(1).owner, 1);313314 assert_ok!(TemplateModule::create_item(315 origin1.clone(),316 1,317 [1, 2, 3].to_vec(),318 1319 ));320 assert_eq!(TemplateModule::nft_item_id(1, 1).data, [1, 2, 3].to_vec());321 assert_eq!(TemplateModule::balance_count(1, 1), 1);322 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);323324 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));325 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));326 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));327 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));328 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));329330 // do approve331 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));332 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);333 assert_ok!(TemplateModule::approve(origin1.clone(), 10, 1, 1));334 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 2);335 assert_eq!(336 TemplateModule::approved(1, (1, 1))[0],337 ApprovePermissions {338 approved: 2,339 amount: 100000000340 }341 );342343 assert_ok!(TemplateModule::transfer_from(344 origin2.clone(),345 1,346 3,347 1,348 1,349 1350 ));351 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 0);352 });353}354355#[test]356fn refungible_approve_and_transfer_from() {357 new_test_ext().execute_with(|| {358 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();359 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();360 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();361 let mode: CollectionMode = CollectionMode::ReFungible(2000, 3);362363 let origin1 = Origin::signed(1);364 let origin2 = Origin::signed(2);365 assert_ok!(TemplateModule::create_collection(366 origin1.clone(),367 col_name1.clone(),368 col_desc1.clone(),369 token_prefix1.clone(),370 mode371 ));372 assert_eq!(TemplateModule::collection(1).owner, 1);373374 assert_ok!(TemplateModule::create_item(375 origin1.clone(),376 1,377 [1, 2, 3].to_vec(),378 1379 ));380 assert_eq!(381 TemplateModule::refungible_item_id(1, 1).data,382 [1, 2, 3].to_vec()383 );384 assert_eq!(385 TemplateModule::refungible_item_id(1, 1).owner[0],386 Ownership {387 owner: 1,388 fraction: 1000389 }390 );391 assert_eq!(TemplateModule::balance_count(1, 1), 1000);392 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);393394 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));395 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));396 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));397 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));398 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));399400 // do approve401 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));402 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);403 assert_ok!(TemplateModule::approve(origin1.clone(), 10, 1, 1));404 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 2);405 assert_eq!(406 TemplateModule::approved(1, (1, 1))[0],407 ApprovePermissions {408 approved: 2,409 amount: 100000000410 }411 );412413 assert_ok!(TemplateModule::transfer_from(414 origin2.clone(),415 1,416 3,417 1,418 1,419 100420 ));421 assert_eq!(TemplateModule::balance_count(1, 1), 900);422 assert_eq!(TemplateModule::balance_count(1, 3), 100);423 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);424 assert_eq!(TemplateModule::address_tokens(1, 3), [1]);425426 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);427 assert_eq!(428 TemplateModule::approved(1, (1, 1))[0],429 ApprovePermissions {430 approved: 10,431 amount: 100000000432 }433 );434 });435}436437#[test]438fn fungible_approve_and_transfer_from() {439 new_test_ext().execute_with(|| {440 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();441 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();442 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();443 let mode: CollectionMode = CollectionMode::Fungible(3);444445 let origin1 = Origin::signed(1);446 let origin2 = Origin::signed(2);447 assert_ok!(TemplateModule::create_collection(448 origin1.clone(),449 col_name1.clone(),450 col_desc1.clone(),451 token_prefix1.clone(),452 mode453 ));454 assert_eq!(TemplateModule::collection(1).owner, 1);455456 assert_ok!(TemplateModule::create_item(457 origin1.clone(),458 1,459 [].to_vec(),460 1461 ));462 assert_eq!(TemplateModule::fungible_item_id(1, 1).owner, 1);463 assert_eq!(TemplateModule::balance_count(1, 1), 1000);464 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);465466 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));467 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));468 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));469 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));470 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));471472 // do approve473 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));474 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);475 assert_ok!(TemplateModule::approve(origin1.clone(), 10, 1, 1));476 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 2);477 assert_eq!(478 TemplateModule::approved(1, (1, 1))[0],479 ApprovePermissions {480 approved: 2,481 amount: 100000000482 }483 );484485 assert_ok!(TemplateModule::transfer_from(486 origin2.clone(),487 1,488 3,489 1,490 1,491 100492 ));493 assert_eq!(TemplateModule::balance_count(1, 1), 900);494 assert_eq!(TemplateModule::balance_count(1, 3), 100);495 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);496 assert_eq!(TemplateModule::address_tokens(1, 3), [2]);497498 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);499 assert_eq!(500 TemplateModule::approved(1, (1, 1))[0],501 ApprovePermissions {502 approved: 10,503 amount: 100000000504 }505 );506507 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));508 assert_ok!(TemplateModule::transfer_from(509 origin2.clone(),510 1,511 3,512 1,513 1,514 900515 ));516 assert_eq!(TemplateModule::balance_count(1, 1), 0);517 assert_eq!(TemplateModule::balance_count(1, 3), 1000);518 assert_eq!(TemplateModule::address_tokens(1, 1), []);519 assert_eq!(TemplateModule::address_tokens(1, 3), [2]);520521 assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 0);522 });523}524525#[test]526fn change_collection_owner() {527 new_test_ext().execute_with(|| {528 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();529 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();530 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();531 let mode: CollectionMode = CollectionMode::NFT(2000);532533 let origin1 = Origin::signed(1);534 assert_ok!(TemplateModule::create_collection(535 origin1.clone(),536 col_name1.clone(),537 col_desc1.clone(),538 token_prefix1.clone(),539 mode540 ));541 assert_ok!(TemplateModule::change_collection_owner(542 origin1.clone(),543 1,544 2545 ));546 assert_eq!(TemplateModule::collection(1).owner, 2);547 });548}549550#[test]551fn destroy_collection() {552 new_test_ext().execute_with(|| {553 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();554 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();555 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();556 let mode: CollectionMode = CollectionMode::NFT(2000);557558 let origin1 = Origin::signed(1);559 assert_ok!(TemplateModule::create_collection(560 origin1.clone(),561 col_name1.clone(),562 col_desc1.clone(),563 token_prefix1.clone(),564 mode565 ));566 assert_ok!(TemplateModule::destroy_collection(origin1.clone(), 1));567 });568}569570#[test]571fn burn_nft_item() {572 new_test_ext().execute_with(|| {573 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();574 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();575 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();576 let mode: CollectionMode = CollectionMode::NFT(2000);577578 let origin1 = Origin::signed(1);579 assert_ok!(TemplateModule::create_collection(580 origin1.clone(),581 col_name1.clone(),582 col_desc1.clone(),583 token_prefix1.clone(),584 mode585 ));586 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));587 assert_ok!(TemplateModule::create_item(588 origin1.clone(),589 1,590 [1, 2, 3].to_vec(),591 1592 ));593594 assert_eq!(TemplateModule::nft_item_id(1, 1).data, [1, 2, 3].to_vec());595596 // check balance (collection with id = 1, user id = 1)597 assert_eq!(TemplateModule::balance_count(1, 1), 1);598599 // burn item600 assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1));601 assert_noop!(602 TemplateModule::burn_item(origin1.clone(), 1, 1),603 "Item does not exists"604 );605606 assert_eq!(TemplateModule::balance_count(1, 1), 0);607 });608}609610#[test]611fn burn_fungible_item() {612 new_test_ext().execute_with(|| {613 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();614 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();615 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();616 let mode: CollectionMode = CollectionMode::Fungible(3);617618 let origin1 = Origin::signed(1);619 assert_ok!(TemplateModule::create_collection(620 origin1.clone(),621 col_name1.clone(),622 col_desc1.clone(),623 token_prefix1.clone(),624 mode625 ));626 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));627 assert_ok!(TemplateModule::create_item(628 origin1.clone(),629 1,630 [].to_vec(),631 1632 ));633634 // check balance (collection with id = 1, user id = 1)635 assert_eq!(TemplateModule::balance_count(1, 1), 1000);636637 // burn item638 assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1));639 assert_noop!(640 TemplateModule::burn_item(origin1.clone(), 1, 1),641 "Item does not exists"642 );643644 assert_eq!(TemplateModule::balance_count(1, 1), 0);645 });646}647648#[test]649fn burn_refungible_item() {650 new_test_ext().execute_with(|| {651 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();652 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();653 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();654 let mode: CollectionMode = CollectionMode::ReFungible(200, 3);655656 let origin1 = Origin::signed(1);657 let origin2 = Origin::signed(2);658 assert_ok!(TemplateModule::create_collection(659 origin1.clone(),660 col_name1.clone(),661 col_desc1.clone(),662 token_prefix1.clone(),663 mode664 ));665 666 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));667 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));668 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));669670 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));671 assert_ok!(TemplateModule::create_item(672 origin2.clone(),673 1,674 [1, 2, 3].to_vec(),675 1676 ));677678 assert_eq!(679 TemplateModule::refungible_item_id(1, 1).data,680 [1, 2, 3].to_vec()681 );682683 // check balance (collection with id = 1, user id = 2)684 assert_eq!(TemplateModule::balance_count(1, 1), 1000);685686 // burn item687 assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1));688 assert_noop!(689 TemplateModule::burn_item(origin1.clone(), 1, 1),690 "Item does not exists"691 );692693 assert_eq!(TemplateModule::balance_count(1, 1), 0);694 });695}696697#[test]698fn add_collection_admin() {699 new_test_ext().execute_with(|| {700 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();701 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();702 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();703 let mode: CollectionMode = CollectionMode::NFT(2000);704705 let origin1 = Origin::signed(1);706 let origin2 = Origin::signed(2);707 let origin3 = Origin::signed(3);708 assert_ok!(TemplateModule::create_collection(709 origin1.clone(),710 col_name1.clone(),711 col_desc1.clone(),712 token_prefix1.clone(),713 mode.clone()714 ));715 assert_ok!(TemplateModule::create_collection(716 origin2.clone(),717 col_name1.clone(),718 col_desc1.clone(),719 token_prefix1.clone(),720 mode.clone()721 ));722 assert_ok!(TemplateModule::create_collection(723 origin3.clone(),724 col_name1.clone(),725 col_desc1.clone(),726 token_prefix1.clone(),727 mode.clone()728 ));729730 assert_eq!(TemplateModule::collection(1).owner, 1);731 assert_eq!(TemplateModule::collection(2).owner, 2);732 assert_eq!(TemplateModule::collection(3).owner, 3);733734 // collection admin735 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));736 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 3));737738 assert_eq!(TemplateModule::admin_list_collection(1).contains(&2), true);739 assert_eq!(TemplateModule::admin_list_collection(1).contains(&3), true);740 });741}742743#[test]744fn remove_collection_admin() {745 new_test_ext().execute_with(|| {746 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();747 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();748 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();749 let mode: CollectionMode = CollectionMode::NFT(2000);750751 let origin1 = Origin::signed(1);752 let origin2 = Origin::signed(2);753 let origin3 = Origin::signed(3);754755 assert_ok!(TemplateModule::create_collection(756 origin1.clone(),757 col_name1.clone(),758 col_desc1.clone(),759 token_prefix1.clone(),760 mode.clone()761 ));762 assert_ok!(TemplateModule::create_collection(763 origin2.clone(),764 col_name1.clone(),765 col_desc1.clone(),766 token_prefix1.clone(),767 mode.clone()768 ));769 assert_ok!(TemplateModule::create_collection(770 origin3.clone(),771 col_name1.clone(),772 col_desc1.clone(),773 token_prefix1.clone(),774 mode.clone()775 ));776777 assert_eq!(TemplateModule::collection(1).owner, 1);778 assert_eq!(TemplateModule::collection(2).owner, 2);779 assert_eq!(TemplateModule::collection(3).owner, 3);780781 // collection admin782 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));783 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 3));784785 assert_eq!(TemplateModule::admin_list_collection(1).contains(&2), true);786 assert_eq!(TemplateModule::admin_list_collection(1).contains(&3), true);787788 // remove admin789 assert_ok!(TemplateModule::remove_collection_admin(790 origin2.clone(),791 1,792 3793 ));794 assert_eq!(TemplateModule::admin_list_collection(1).contains(&3), false);795 });796}797798#[test]799fn balance_of() {800 new_test_ext().execute_with(|| {801 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();802 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();803 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();804 let nft_mode: CollectionMode = CollectionMode::NFT(2000);805 let furg_mode: CollectionMode = CollectionMode::Fungible(3);806 let refung_mode: CollectionMode = CollectionMode::ReFungible(2000, 3);807808 let origin1 = Origin::signed(1);809810 assert_ok!(TemplateModule::create_collection(811 origin1.clone(),812 col_name1.clone(),813 col_desc1.clone(),814 token_prefix1.clone(),815 nft_mode.clone()816 ));817 assert_ok!(TemplateModule::create_collection(818 origin1.clone(),819 col_name1.clone(),820 col_desc1.clone(),821 token_prefix1.clone(),822 furg_mode.clone()823 ));824 assert_ok!(TemplateModule::create_collection(825 origin1.clone(),826 col_name1.clone(),827 col_desc1.clone(),828 token_prefix1.clone(),829 refung_mode.clone()830 ));831832 assert_eq!(TemplateModule::collection(1).owner, 1);833 assert_eq!(TemplateModule::collection(2).owner, 1);834 assert_eq!(TemplateModule::collection(3).owner, 1);835836 // check balance before837 assert_eq!(TemplateModule::balance_count(1, 1), 0);838 assert_eq!(TemplateModule::balance_count(2, 1), 0);839 assert_eq!(TemplateModule::balance_count(3, 1), 0);840841 // create item842 assert_ok!(TemplateModule::create_item(843 origin1.clone(),844 1,845 [1, 1, 1].to_vec(),846 1847 ));848849 assert_ok!(TemplateModule::create_item(850 origin1.clone(),851 2,852 [].to_vec(),853 1854 ));855856 assert_ok!(TemplateModule::create_item(857 origin1.clone(),858 3,859 [1, 1, 1].to_vec(),860 1861 ));862863 // check balance (collection with id = 1, user id = 1)864 assert_eq!(TemplateModule::balance_count(1, 1), 1);865 assert_eq!(TemplateModule::balance_count(2, 1), 1000);866 assert_eq!(TemplateModule::balance_count(3, 1), 1000);867 assert_eq!(TemplateModule::nft_item_id(1, 1).owner, 1);868 assert_eq!(TemplateModule::fungible_item_id(2, 1).owner, 1);869 assert_eq!(TemplateModule::refungible_item_id(3, 1).owner[0].owner, 1);870 });871}872873#[test]874fn approve() {875 new_test_ext().execute_with(|| {876 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();877 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();878 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();879 let nft_mode: CollectionMode = CollectionMode::NFT(2000);880 let origin1 = Origin::signed(1);881882 assert_ok!(TemplateModule::create_collection(883 origin1.clone(),884 col_name1.clone(),885 col_desc1.clone(),886 token_prefix1.clone(),887 nft_mode.clone()888 ));889890 assert_eq!(TemplateModule::collection(1).owner, 1);891892 // create item893 assert_ok!(TemplateModule::create_item(894 origin1.clone(),895 1,896 [1, 1, 1].to_vec(),897 1898 ));899900 // approve901 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));902 assert_eq!(TemplateModule::approved(1, (1, 1))[0].approved, 2);903 });904}905906#[test]907fn transfer_from() {908 new_test_ext().execute_with(|| {909 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();910 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();911 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();912 let mode: CollectionMode = CollectionMode::NFT(2000);913 let origin1 = Origin::signed(1);914 let origin2 = Origin::signed(2);915916 assert_ok!(TemplateModule::create_collection(917 origin1.clone(),918 col_name1.clone(),919 col_desc1.clone(),920 token_prefix1.clone(),921 mode922 ));923924 assert_eq!(TemplateModule::collection(1).owner, 1);925926 // create item927 assert_ok!(TemplateModule::create_item(928 origin1.clone(),929 1,930 [1, 1, 1].to_vec(),931 1932 ));933934 // approve935 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));936 assert_eq!(TemplateModule::approved(1, (1, 1))[0].approved, 2);937938 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));939 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));940 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));941 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));942 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));943944 assert_ok!(TemplateModule::transfer_from(945 origin2.clone(),946 1,947 2,948 1,949 1,950 1951 ));952953 // after transfer954 assert_eq!(TemplateModule::balance_count(1, 1), 0);955 assert_eq!(TemplateModule::balance_count(1, 2), 1);956 });957}runtime/src/lib.rsdiffbeforeafterboth--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -111,7 +111,7 @@
spec_name: create_runtime_str!("nft"),
impl_name: create_runtime_str!("nft"),
authoring_version: 1,
- spec_version: 1,
+ spec_version: 2,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,