difftreelog
NFTPAR-142 Off-chain and on-chain data schema.
in: master
6 files changed
node/src/chain_spec.rsdiffbeforeafterboth--- a/node/src/chain_spec.rs
+++ b/node/src/chain_spec.rs
@@ -159,17 +159,18 @@
1,
CollectionType {
owner: get_account_id_from_seed::<sr25519::Public>("Alice"),
- mode: CollectionMode::NFT(50),
+ mode: CollectionMode::NFT,
access: AccessMode::Normal,
decimal_points: 0,
name: vec![],
description: vec![],
token_prefix: vec![],
- custom_data_size: 50,
mint_mode: false,
offchain_schema: vec![],
sponsor: get_account_id_from_seed::<sr25519::Public>("Alice"),
unconfirmed_sponsor: get_account_id_from_seed::<sr25519::Public>("Alice"),
+ const_on_chain_schema: vec![],
+ variable_on_chain_schema: vec![]
},
)],
nft_item_id: vec![],
pallets/nft/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/nft/src/benchmarking.rs
+++ b/pallets/nft/src/benchmarking.rs
@@ -9,6 +9,19 @@
const SEED: u32 = 1;
+ fn default_nft_data() -> CreateItemData {
+ CreateItemData::NFT(CreateNftData { const_data: vec![1, 2, 3], variable_data: vec![3, 2, 1] })
+ }
+
+ fn default_fungible_data () -> CreateItemData {
+ CreateItemData::Fungible(CreateFungibleData { })
+ }
+
+ fn default_re_fungible_data () -> CreateItemData {
+ CreateItemData::ReFungible(CreateReFungibleData { const_data: vec![1, 2, 3], variable_data: vec![3, 2, 1] })
+ }
+
+
benchmarks! {
_ {}
@@ -17,7 +30,7 @@
let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ let mode: CollectionMode = CollectionMode::NFT;
let caller: T::AccountId = account("caller", 0, SEED);
}: create_collection(RawOrigin::Signed(caller.clone()), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode)
verify {
@@ -28,7 +41,7 @@
let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ let mode: CollectionMode = CollectionMode::NFT;
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
}: destroy_collection(RawOrigin::Signed(caller.clone()), 2)
@@ -37,7 +50,7 @@
let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ let mode: CollectionMode = CollectionMode::NFT;
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
let whitelist_account: T::AccountId = account("admin", 0, SEED);
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
@@ -47,7 +60,7 @@
let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ let mode: CollectionMode = CollectionMode::NFT;
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
let whitelist_account: T::AccountId = account("admin", 0, SEED);
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
@@ -58,7 +71,7 @@
let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ let mode: CollectionMode = CollectionMode::NFT;
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
}: set_public_access_mode(RawOrigin::Signed(caller.clone()), 2, AccessMode::WhiteList)
@@ -67,7 +80,7 @@
let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ let mode: CollectionMode = CollectionMode::NFT;
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
}: set_mint_permission(RawOrigin::Signed(caller.clone()), 2, true)
@@ -76,7 +89,7 @@
let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ let mode: CollectionMode = CollectionMode::NFT;
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
let new_owner: T::AccountId = account("admin", 0, SEED);
@@ -86,7 +99,7 @@
let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ let mode: CollectionMode = CollectionMode::NFT;
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
let new_admin: T::AccountId = account("admin", 0, SEED);
@@ -96,7 +109,7 @@
let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ let mode: CollectionMode = CollectionMode::NFT;
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
let new_admin: T::AccountId = account("admin", 0, SEED);
@@ -107,7 +120,7 @@
let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ let mode: CollectionMode = CollectionMode::NFT;
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
}: set_collection_sponsor(RawOrigin::Signed(caller.clone()), 2, caller.clone())
@@ -116,7 +129,7 @@
let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ let mode: CollectionMode = CollectionMode::NFT;
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
Nft::<T>::set_collection_sponsor(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone())?;
@@ -126,7 +139,7 @@
let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ let mode: CollectionMode = CollectionMode::NFT;
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
Nft::<T>::set_collection_sponsor(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone())?;
@@ -138,26 +151,32 @@
let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ let mode: CollectionMode = CollectionMode::NFT;
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
-
- }: create_item(RawOrigin::Signed(caller.clone()), 2, [1,2,3].to_vec(), caller.clone())
+ let data = default_nft_data();
+
+ }: create_item(RawOrigin::Signed(caller.clone()), 2, caller.clone(), data)
#[extra]
create_item_nft_large {
let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ let mode: CollectionMode = CollectionMode::NFT;
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
- let mut item_large: Vec<u8> = Vec::new();
+ let nft_data = CreateNftData {
+ const_data: vec![],
+ variable_data: vec![]
+ };
for i in 0..1998 {
- item_large.push(10);
+ nft_data.const_data.push(10);
+ nft_data.variable_data.push(10);
}
+ let mut data = CreateItemData::NFT(nft_data);
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
- }: create_item(RawOrigin::Signed(caller.clone()), 2, item_large, caller.clone())
+ }: create_item(RawOrigin::Signed(caller.clone()), 2, caller.clone(), data)
// fungible item
create_item_fungible {
@@ -167,28 +186,31 @@
let mode: CollectionMode = CollectionMode::Fungible(3);
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+ let data = default_fungible_data();
- }: create_item(RawOrigin::Signed(caller.clone()), 2, [].to_vec(), caller.clone())
+ }: create_item(RawOrigin::Signed(caller.clone()), 2, caller.clone(), data)
// refungible item
create_item_refungible {
let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
- let mode: CollectionMode = CollectionMode::ReFungible(3, 3);
+ let mode: CollectionMode = CollectionMode::ReFungible(3);
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+ let data = default_re_fungible_data();
- }: create_item(RawOrigin::Signed(caller.clone()), 2, [1,2,3].to_vec(), caller.clone())
+ }: create_item(RawOrigin::Signed(caller.clone()), 2, caller.clone(), data)
burn_item {
let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ let mode: CollectionMode = CollectionMode::NFT;
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
- Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [1, 2, 3].to_vec(), caller.clone())?;
+ let data = default_nft_data();
+ Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?;
}: burn_item(RawOrigin::Signed(caller.clone()), 2, 1)
@@ -196,11 +218,12 @@
let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ let mode: CollectionMode = CollectionMode::NFT;
let recipient: T::AccountId = account("recipient", 0, SEED);
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
- Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [1, 2, 3].to_vec(), caller.clone())?;
+ let data = default_nft_data();
+ Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?;
}: transfer(RawOrigin::Signed(caller.clone()), recipient.clone(), 2, 1, 1)
@@ -212,7 +235,8 @@
let recipient: T::AccountId = account("recipient", 0, SEED);
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
- Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [].to_vec(), caller.clone())?;
+ let data = default_fungible_data();
+ Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?;
}: transfer(RawOrigin::Signed(caller.clone()), recipient.clone(), 2, 1, 1)
@@ -220,11 +244,12 @@
let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
- let mode: CollectionMode = CollectionMode::ReFungible(3,3);
+ let mode: CollectionMode = CollectionMode::ReFungible(3);
let recipient: T::AccountId = account("recipient", 0, SEED);
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
- Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [1,2,3].to_vec(), caller.clone())?;
+ let data = default_re_fungible_data();
+ Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?;
}: transfer(RawOrigin::Signed(caller.clone()), recipient.clone(), 2, 1, 1)
@@ -232,11 +257,12 @@
let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
- let mode: CollectionMode = CollectionMode::ReFungible(3,3);
+ let mode: CollectionMode = CollectionMode::ReFungible(3);
let recipient: T::AccountId = account("recipient", 0, SEED);
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
- Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [1,2,3].to_vec(), caller.clone())?;
+ let data = default_re_fungible_data();
+ Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?;
}: approve(RawOrigin::Signed(caller.clone()), recipient.clone(), 2, 1)
@@ -245,11 +271,12 @@
let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(300);
+ let mode: CollectionMode = CollectionMode::NFT;
let recipient: T::AccountId = account("recipient", 0, SEED);
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
- Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [1,2,3].to_vec(), caller.clone())?;
+ let data = default_nft_data();
+ Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?;
Nft::<T>::approve(RawOrigin::Signed(caller.clone()).into(), recipient.clone(), 2, 1)?;
}: transfer_from(RawOrigin::Signed(caller.clone()), caller.clone(), recipient.clone(), 2, 1, 1)
@@ -263,7 +290,8 @@
let recipient: T::AccountId = account("recipient", 0, SEED);
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
- Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [].to_vec(), caller.clone())?;
+ let data = default_fungible_data();
+ Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?;
Nft::<T>::approve(RawOrigin::Signed(caller.clone()).into(), recipient.clone(), 2, 1)?;
}: transfer_from(RawOrigin::Signed(caller.clone()), caller.clone(), recipient.clone(), 2, 1, 1)
@@ -273,11 +301,12 @@
let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
- let mode: CollectionMode = CollectionMode::ReFungible(3,3);
+ let mode: CollectionMode = CollectionMode::ReFungible(3);
let recipient: T::AccountId = account("recipient", 0, SEED);
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
- Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [1,2,3].to_vec(), caller.clone())?;
+ let data = default_re_fungible_data();
+ Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?;
Nft::<T>::approve(RawOrigin::Signed(caller.clone()).into(), recipient.clone(), 2, 1)?;
}: transfer_from(RawOrigin::Signed(caller.clone()), caller.clone(), recipient.clone(), 2, 1, 1)
@@ -286,9 +315,39 @@
let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
- let mode: CollectionMode = CollectionMode::ReFungible(3,3);
+ let mode: CollectionMode = CollectionMode::ReFungible(3);
let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
}: set_offchain_schema(RawOrigin::Signed(caller.clone()), 2, [1,2,3].to_vec())
- }
\ No newline at end of file
+
+ set_const_on_chain_schema {
+ let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+ let mode: CollectionMode = CollectionMode::ReFungible(3);
+ let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+ Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+ }: set_const_on_chain_schema(RawOrigin::Signed(caller.clone()), 2, [1,2,3].to_vec())
+
+ set_variable_on_chain_schema {
+ let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+ let mode: CollectionMode = CollectionMode::ReFungible(3);
+ let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+ Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+ }: set_variable_on_chain_schema(RawOrigin::Signed(caller.clone()), 2, [1,2,3].to_vec())
+
+ set_variable_meta_data {
+ let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT;
+ let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+ Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+ let data = default_nft_data();
+ Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?;
+
+ }: set_variable_meta_data(RawOrigin::Signed(caller.clone()), 2, 1, [1, 2, 3].to_vec())
+}
\ No newline at end of file
pallets/nft/src/default_weights.rsdiffbeforeafterboth--- a/pallets/nft/src/default_weights.rs
+++ b/pallets/nft/src/default_weights.rs
@@ -92,4 +92,19 @@
.saturating_add(DbWeight::get().reads(2 as Weight))
.saturating_add(DbWeight::get().writes(1 as Weight))
}
+ fn set_const_on_chain_schema() -> Weight {
+ (11_100_000 as Weight)
+ .saturating_add(DbWeight::get().reads(2 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn set_variable_on_chain_schema() -> Weight {
+ (11_100_000 as Weight)
+ .saturating_add(DbWeight::get().reads(2 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn set_variable_meta_data() -> Weight {
+ (17_500_000 as Weight)
+ .saturating_add(DbWeight::get().reads(2 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
}
pallets/nft/src/lib.rsdiffbeforeafterboth1#![cfg_attr(not(feature = "std"), no_std)]23#[cfg(feature = "std")]4pub use std::*;56#[cfg(feature = "std")]7pub use serde::*;89use codec::{Decode, Encode};10pub use frame_support::{11 construct_runtime, decl_event, decl_module, decl_storage,12 dispatch::DispatchResult,13 ensure, parameter_types,14 traits::{15 Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,16 Randomness, WithdrawReason,17 },18 weights::{19 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},20 DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,21 WeightToFeePolynomial,22 },23 IsSubType, StorageValue,24};25// use frame_support::weights::{Weight, constants::RocksDbWeight as DbWeight};2627use frame_system::{self as system, ensure_signed, ensure_root};28use sp_runtime::sp_std::prelude::Vec;29use sp_runtime::{30 traits::{31 DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SaturatedConversion, Saturating,32 SignedExtension, Zero,33 },34 transaction_validity::{35 InvalidTransaction, TransactionPriority, TransactionValidity, TransactionValidityError,36 ValidTransaction,37 },38 FixedPointOperand, FixedU128,39};4041#[cfg(test)]42mod mock;4344#[cfg(test)]45mod tests;4647mod default_weights;4849// Structs50// #region5152#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]53#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]54pub enum CollectionMode {55 Invalid,56 // custom data size57 NFT(u32),58 // decimal points59 Fungible(u32),60 // custom data size and decimal points61 ReFungible(u32, u32),62}6364impl Into<u8> for CollectionMode {65 fn into(self) -> u8 {66 match self {67 CollectionMode::Invalid => 0,68 CollectionMode::NFT(_) => 1,69 CollectionMode::Fungible(_) => 2,70 CollectionMode::ReFungible(_, _) => 3,71 }72 }73}7475#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]76#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]77pub enum AccessMode {78 Normal,79 WhiteList,80}81impl Default for AccessMode {82 fn default() -> Self {83 Self::Normal84 }85}8687impl Default for CollectionMode {88 fn default() -> Self {89 Self::Invalid90 }91}9293#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]94#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]95pub struct Ownership<AccountId> {96 pub owner: AccountId,97 pub fraction: u128,98}99100#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]101#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]102pub struct CollectionType<AccountId> {103 pub owner: AccountId,104 pub mode: CollectionMode,105 pub access: AccessMode,106 pub decimal_points: u32,107 pub name: Vec<u16>, // 64 include null escape char108 pub description: Vec<u16>, // 256 include null escape char109 pub token_prefix: Vec<u8>, // 16 include null escape char110 pub custom_data_size: u32,111 pub mint_mode: bool,112 pub offchain_schema: Vec<u8>,113 pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender114 pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship115}116117#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]118#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]119pub struct CollectionAdminsType<AccountId> {120 pub admin: AccountId,121 pub collection_id: u64,122}123124#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]125#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]126pub struct NftItemType<AccountId> {127 pub collection: u64,128 pub owner: AccountId,129 pub data: Vec<u8>,130}131132#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]133#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]134pub struct FungibleItemType<AccountId> {135 pub collection: u64,136 pub owner: AccountId,137 pub value: u128,138}139140#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]141#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]142pub struct ReFungibleItemType<AccountId> {143 pub collection: u64,144 pub owner: Vec<Ownership<AccountId>>,145 pub data: Vec<u8>,146}147148#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]149#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]150pub struct ApprovePermissions<AccountId> {151 pub approved: AccountId,152 pub amount: u64,153}154155#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]156#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]157pub struct VestingItem<AccountId, Moment> {158 pub sender: AccountId,159 pub recipient: AccountId,160 pub collection_id: u64,161 pub item_id: u64,162 pub amount: u64,163 pub vesting_date: Moment,164}165166#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]167#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]168pub struct BasketItem<AccountId, BlockNumber> {169 pub address: AccountId,170 pub start_block: BlockNumber,171}172173#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]174#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]175pub struct ChainLimits {176 pub collection_numbers_limit: u64,177 pub account_token_ownership_limit: u64,178 pub collections_admins_limit: u64,179 pub custom_data_limit: u32,180181 // Timeouts for item types in passed blocks182 pub nft_sponsor_transfer_timeout: u32,183 pub fungible_sponsor_transfer_timeout: u32,184 pub refungible_sponsor_transfer_timeout: u32,185}186187pub trait WeightInfo {188 fn create_collection() -> Weight;189 fn destroy_collection() -> Weight;190 fn add_to_white_list() -> Weight;191 fn remove_from_white_list() -> Weight;192 fn set_public_access_mode() -> Weight;193 fn set_mint_permission() -> Weight;194 fn change_collection_owner() -> Weight;195 fn add_collection_admin() -> Weight;196 fn remove_collection_admin() -> Weight;197 fn set_collection_sponsor() -> Weight;198 fn confirm_sponsorship() -> Weight;199 fn remove_collection_sponsor() -> Weight;200 fn create_item(s: usize, ) -> Weight;201 fn burn_item() -> Weight;202 fn transfer() -> Weight;203 fn approve() -> Weight;204 fn transfer_from() -> Weight;205 fn set_offchain_schema() -> Weight;206}207208pub trait Trait: system::Trait + Sized {209 type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;210211 /// Weight information for extrinsics in this pallet.212 type WeightInfo: WeightInfo;213}214215#[cfg(feature = "runtime-benchmarks")]216mod benchmarking;217218// #endregion219220decl_storage! {221 trait Store for Module<T: Trait> as Nft {222223 // Private members224 NextCollectionID: u64;225 CreatedCollectionCount: u64;226 ChainVersion: u64;227 ItemListIndex: map hasher(blake2_128_concat) u64 => u64;228229 // Chain limits struct230 pub ChainLimit get(fn chain_limit) config(): ChainLimits;231232 // Bound counters233 CollectionCount: u64;234 pub AccountItemCount get(fn account_item_count): map hasher(identity) T::AccountId => u64;235236 // Basic collections237 pub Collection get(fn collection) config(): map hasher(identity) u64 => CollectionType<T::AccountId>;238 pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec<T::AccountId>;239 pub WhiteList get(fn white_list): map hasher(identity) u64 => Vec<T::AccountId>;240241 /// Balance owner per collection map242 pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => u64;243244 /// second parameter: item id + owner account id245 pub ApprovedList get(fn approved): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) (u64, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;246247 /// Item collections248 pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;249 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;250 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;251252 /// Index list253 pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;254255 /// Tokens transfer baskets256 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;257 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => Vec<BasketItem<T::AccountId, T::BlockNumber>>;258 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;259260 // Sponsorship261 pub ContractSponsor get(fn contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;262 pub UnconfirmedContractSponsor get(fn unconfirmed_contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;263 }264 add_extra_genesis {265 build(|config: &GenesisConfig<T>| {266 // Modification of storage267 for (_num, _c) in &config.collection {268 <Module<T>>::init_collection(_c);269 }270271 for (_num, _q, _i) in &config.nft_item_id {272 <Module<T>>::init_nft_token(_i);273 }274275 for (_num, _q, _i) in &config.fungible_item_id {276 <Module<T>>::init_fungible_token(_i);277 }278279 for (_num, _q, _i) in &config.refungible_item_id {280 <Module<T>>::init_refungible_token(_i);281 }282 })283 }284}285286decl_event!(287 pub enum Event<T>288 where289 AccountId = <T as system::Trait>::AccountId,290 {291 /// New collection was created292 /// 293 /// # Arguments294 /// 295 /// * collection_id: Globally unique identifier of newly created collection.296 /// 297 /// * mode: [CollectionMode] converted into u8.298 /// 299 /// * account_id: Collection owner.300 Created(u64, u8, AccountId),301302 /// New item was created.303 /// 304 /// # Arguments305 /// 306 /// * collection_id: Id of the collection where item was created.307 /// 308 /// * item_id: Id of an item. Unique within the collection.309 ItemCreated(u64, u64),310311 /// Collection item was burned.312 /// 313 /// # Arguments314 /// 315 /// collection_id.316 /// 317 /// item_id: Identifier of burned NFT.318 ItemDestroyed(u64, u64),319 }320);321322decl_module! {323 pub struct Module<T: Trait> for enum Call where origin: T::Origin {324325 fn deposit_event() = default;326327 fn on_initialize(now: T::BlockNumber) -> Weight {328329 if ChainVersion::get() < 2330 {331 let value = NextCollectionID::get();332 CreatedCollectionCount::put(value);333 ChainVersion::put(2);334 }335336 0337 }338339 /// This method creates a Collection of NFTs. Each Token may have multiple properties encoded as an array of bytes of certain length. The initial owner and admin of the collection are set to the address that signed the transaction. Both addresses can be changed later.340 /// 341 /// # Permissions342 /// 343 /// * Anyone.344 /// 345 /// # Arguments346 /// 347 /// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.348 /// 349 /// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.350 /// 351 /// * token_prefix: UTF-8 string with token prefix.352 /// 353 /// * mode: [CollectionMode] collection type and type dependent data.354 // returns collection ID355 #[weight = T::WeightInfo::create_collection()]356 pub fn create_collection(origin,357 collection_name: Vec<u16>,358 collection_description: Vec<u16>,359 token_prefix: Vec<u8>,360 mode: CollectionMode) -> DispatchResult {361362 // Anyone can create a collection363 let who = ensure_signed(origin)?;364 let custom_data_size = match mode {365 CollectionMode::NFT(size) => {366367 // bound Custom data size368 ensure!(size < ChainLimit::get().custom_data_limit, "Custom data size bound exceeded");369 size370 },371 CollectionMode::ReFungible(size, _) => {372373 // bound Custom data size374 ensure!(size < ChainLimit::get().custom_data_limit, "Custom data size bound exceeded");375 size376 },377 _ => 0378 };379380 let decimal_points = match mode {381 CollectionMode::Fungible(points) => points,382 CollectionMode::ReFungible(_, points) => points,383 _ => 0384 };385386 // bound Total number of collections387 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, "Total collections bound exceeded");388389 // check params390 ensure!(decimal_points <= 4, "decimal_points parameter must be lower than 4");391392 let mut name = collection_name.to_vec();393 name.push(0);394 ensure!(name.len() <= 64, "Collection name can not be longer than 63 char");395396 let mut description = collection_description.to_vec();397 description.push(0);398 ensure!(name.len() <= 256, "Collection description can not be longer than 255 char");399400 let mut prefix = token_prefix.to_vec();401 prefix.push(0);402 ensure!(prefix.len() <= 16, "Token prefix can not be longer than 15 char");403404 // Generate next collection ID405 let next_id = CreatedCollectionCount::get()406 .checked_add(1)407 .expect("collection id error");408409 // bound counter410 let total = CollectionCount::get()411 .checked_add(1)412 .expect("collection counter error");413414 CreatedCollectionCount::put(next_id);415 CollectionCount::put(total);416417 // Create new collection418 let new_collection = CollectionType {419 owner: who.clone(),420 name: name,421 mode: mode.clone(),422 mint_mode: false,423 access: AccessMode::Normal,424 description: description,425 decimal_points: decimal_points,426 token_prefix: prefix,427 offchain_schema: Vec::new(),428 custom_data_size: custom_data_size,429 sponsor: T::AccountId::default(),430 unconfirmed_sponsor: T::AccountId::default(),431 };432433 // Add new collection to map434 <Collection<T>>::insert(next_id, new_collection);435436 // call event437 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));438439 Ok(())440 }441442 /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.443 /// 444 /// # Permissions445 /// 446 /// * Collection Owner.447 /// 448 /// # Arguments449 /// 450 /// * collection_id: collection to destroy.451 #[weight = T::WeightInfo::destroy_collection()]452 pub fn destroy_collection(origin, collection_id: u64) -> DispatchResult {453454 let sender = ensure_signed(origin)?;455 Self::check_owner_permissions(collection_id, sender)?;456457 <AddressTokens<T>>::remove_prefix(collection_id);458 <ApprovedList<T>>::remove_prefix(collection_id);459 <Balance<T>>::remove_prefix(collection_id);460 <ItemListIndex>::remove(collection_id);461 <AdminList<T>>::remove(collection_id);462 <Collection<T>>::remove(collection_id);463 <WhiteList<T>>::remove(collection_id);464465 <NftItemList<T>>::remove_prefix(collection_id);466 <FungibleItemList<T>>::remove_prefix(collection_id);467 <ReFungibleItemList<T>>::remove_prefix(collection_id);468469 <NftTransferBasket<T>>::remove_prefix(collection_id);470 <FungibleTransferBasket<T>>::remove_prefix(collection_id);471 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);472473 if CollectionCount::get() > 0474 {475 // bound couter476 let total = CollectionCount::get()477 .checked_sub(1)478 .expect("collection counter error");479480 CollectionCount::put(total);481 }482483 Ok(())484 }485486 /// Add an address to white list.487 /// 488 /// # Permissions489 /// 490 /// * Collection Owner491 /// * Collection Admin492 /// 493 /// # Arguments494 /// 495 /// * collection_id.496 /// 497 /// * address.498 #[weight = T::WeightInfo::add_to_white_list()]499 pub fn add_to_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{500501 let sender = ensure_signed(origin)?;502 Self::check_owner_or_admin_permissions(collection_id, sender)?;503504 let mut white_list_collection: Vec<T::AccountId>;505 if <WhiteList<T>>::contains_key(collection_id) {506 white_list_collection = <WhiteList<T>>::get(collection_id);507 if !white_list_collection.contains(&address.clone())508 {509 white_list_collection.push(address.clone());510 }511 }512 else {513 white_list_collection = Vec::new();514 white_list_collection.push(address.clone());515 }516517 <WhiteList<T>>::insert(collection_id, white_list_collection);518 Ok(())519 }520521 /// Remove an address from white list.522 /// 523 /// # Permissions524 /// 525 /// * Collection Owner526 /// * Collection Admin527 /// 528 /// # Arguments529 /// 530 /// * collection_id.531 /// 532 /// * address.533 #[weight = T::WeightInfo::remove_from_white_list()]534 pub fn remove_from_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{535536 let sender = ensure_signed(origin)?;537 Self::check_owner_or_admin_permissions(collection_id, sender)?;538539 if <WhiteList<T>>::contains_key(collection_id) {540 let mut white_list_collection = <WhiteList<T>>::get(collection_id);541 if white_list_collection.contains(&address.clone())542 {543 white_list_collection.retain(|i| *i != address.clone());544 <WhiteList<T>>::insert(collection_id, white_list_collection);545 }546 }547548 Ok(())549 }550551 /// Toggle between normal and white list access for the methods with access for `Anyone`.552 /// 553 /// # Permissions554 /// 555 /// * Collection Owner.556 /// 557 /// # Arguments558 /// 559 /// * collection_id.560 /// 561 /// * mode: [AccessMode]562 #[weight = T::WeightInfo::set_public_access_mode()]563 pub fn set_public_access_mode(origin, collection_id: u64, mode: AccessMode) -> DispatchResult564 {565 let sender = ensure_signed(origin)?;566567 Self::check_owner_permissions(collection_id, sender)?;568 let mut target_collection = <Collection<T>>::get(collection_id);569 target_collection.access = mode;570 <Collection<T>>::insert(collection_id, target_collection);571572 Ok(())573 }574575 /// Allows Anyone to create tokens if:576 /// * White List is enabled, and577 /// * Address is added to white list, and578 /// * This method was called with True parameter579 /// 580 /// # Permissions581 /// * Collection Owner582 ///583 /// # Arguments584 /// 585 /// * collection_id.586 /// 587 /// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.588 #[weight = T::WeightInfo::set_mint_permission()]589 pub fn set_mint_permission(origin, collection_id: u64, mint_permission: bool) -> DispatchResult590 {591 let sender = ensure_signed(origin)?;592593 Self::check_owner_permissions(collection_id, sender)?;594 let mut target_collection = <Collection<T>>::get(collection_id);595 target_collection.mint_mode = mint_permission;596 <Collection<T>>::insert(collection_id, target_collection);597598 Ok(())599 }600601 /// Change the owner of the collection.602 /// 603 /// # Permissions604 /// 605 /// * Collection Owner.606 /// 607 /// # Arguments608 /// 609 /// * collection_id.610 /// 611 /// * new_owner.612 #[weight = T::WeightInfo::change_collection_owner()]613 pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {614615 let sender = ensure_signed(origin)?;616 Self::check_owner_permissions(collection_id, sender)?;617 let mut target_collection = <Collection<T>>::get(collection_id);618 target_collection.owner = new_owner;619 <Collection<T>>::insert(collection_id, target_collection);620621 Ok(())622 }623624 /// Adds an admin of the Collection.625 /// NFT Collection can be controlled by multiple admin addresses (some which can also be servers, for example). Admins can issue and burn NFTs, as well as add and remove other admins, but cannot change NFT or Collection ownership. 626 /// 627 /// # Permissions628 /// 629 /// * Collection Owner.630 /// * Collection Admin.631 /// 632 /// # Arguments633 /// 634 /// * collection_id: ID of the Collection to add admin for.635 /// 636 /// * new_admin_id: Address of new admin to add.637 #[weight = T::WeightInfo::add_collection_admin()]638 pub fn add_collection_admin(origin, collection_id: u64, new_admin_id: T::AccountId) -> DispatchResult {639640 let sender = ensure_signed(origin)?;641 Self::check_owner_or_admin_permissions(collection_id, sender)?;642 let mut admin_arr: Vec<T::AccountId> = Vec::new();643644 if <AdminList<T>>::contains_key(collection_id)645 {646 admin_arr = <AdminList<T>>::get(collection_id);647 ensure!(!admin_arr.contains(&new_admin_id), "Account already has admin role");648 }649650 // Number of collection admins651 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, "Number of collection admins bound exceeded");652653 admin_arr.push(new_admin_id);654 <AdminList<T>>::insert(collection_id, admin_arr);655656 Ok(())657 }658659 /// Remove admin address of the Collection. An admin address can remove itself. List of admins may become empty, in which case only Collection Owner will be able to add an Admin.660 ///661 /// # Permissions662 /// 663 /// * Collection Owner.664 /// * Collection Admin.665 /// 666 /// # Arguments667 /// 668 /// * collection_id: ID of the Collection to remove admin for.669 /// 670 /// * account_id: Address of admin to remove.671 #[weight = T::WeightInfo::remove_collection_admin()]672 pub fn remove_collection_admin(origin, collection_id: u64, account_id: T::AccountId) -> DispatchResult {673674 let sender = ensure_signed(origin)?;675 Self::check_owner_or_admin_permissions(collection_id, sender)?;676677 if <AdminList<T>>::contains_key(collection_id)678 {679 let mut admin_arr = <AdminList<T>>::get(collection_id);680 admin_arr.retain(|i| *i != account_id);681 <AdminList<T>>::insert(collection_id, admin_arr);682 }683684 Ok(())685 }686687 /// # Permissions688 /// 689 /// * Collection Owner690 /// 691 /// # Arguments692 /// 693 /// * collection_id.694 /// 695 /// * new_sponsor.696 #[weight = T::WeightInfo::set_collection_sponsor()]697 pub fn set_collection_sponsor(origin, collection_id: u64, new_sponsor: T::AccountId) -> DispatchResult {698699 let sender = ensure_signed(origin)?;700 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");701702 let mut target_collection = <Collection<T>>::get(collection_id);703 ensure!(sender == target_collection.owner, "You do not own this collection");704705 target_collection.unconfirmed_sponsor = new_sponsor;706 <Collection<T>>::insert(collection_id, target_collection);707708 Ok(())709 }710711 /// # Permissions712 /// 713 /// * Sponsor.714 /// 715 /// # Arguments716 /// 717 /// * collection_id.718 #[weight = T::WeightInfo::confirm_sponsorship()]719 pub fn confirm_sponsorship(origin, collection_id: u64) -> DispatchResult {720721 let sender = ensure_signed(origin)?;722 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");723724 let mut target_collection = <Collection<T>>::get(collection_id);725 ensure!(sender == target_collection.unconfirmed_sponsor, "This address is not set as sponsor, use setCollectionSponsor first");726727 target_collection.sponsor = target_collection.unconfirmed_sponsor;728 target_collection.unconfirmed_sponsor = T::AccountId::default();729 <Collection<T>>::insert(collection_id, target_collection);730731 Ok(())732 }733734 /// Switch back to pay-per-own-transaction model.735 ///736 /// # Permissions737 ///738 /// * Collection owner.739 /// 740 /// # Arguments741 /// 742 /// * collection_id.743 #[weight = T::WeightInfo::remove_collection_sponsor()]744 pub fn remove_collection_sponsor(origin, collection_id: u64) -> DispatchResult {745746 let sender = ensure_signed(origin)?;747 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");748749 let mut target_collection = <Collection<T>>::get(collection_id);750 ensure!(sender == target_collection.owner, "You do not own this collection");751752 target_collection.sponsor = T::AccountId::default();753 <Collection<T>>::insert(collection_id, target_collection);754755 Ok(())756 }757758 /// This method creates a concrete instance of NFT Collection created with CreateCollection method.759 /// 760 /// # Permissions761 /// 762 /// * Collection Owner.763 /// * Collection Admin.764 /// * Anyone if765 /// * White List is enabled, and766 /// * Address is added to white list, and767 /// * MintPermission is enabled (see SetMintPermission method)768 /// 769 /// # Arguments770 /// 771 /// * collection_id: ID of the collection.772 /// 773 /// * properties: Array of bytes that contains NFT properties. Since NFT Module is agnostic of properties meaning, it is treated purely as an array of bytes.774 /// 775 /// * owner: Address, initial owner of the NFT.776 // #[weight =777 // (130_000_000 as Weight)778 // .saturating_add((2135 as Weight).saturating_mul((properties.len() as u64) as Weight))779 // .saturating_add(RocksDbWeight::get().reads(10 as Weight))780 // .saturating_add(RocksDbWeight::get().writes(8 as Weight))]781782 #[weight = T::WeightInfo::create_item(properties.len())]783 pub fn create_item(origin, collection_id: u64, properties: Vec<u8>, owner: T::AccountId) -> DispatchResult {784785 let sender = ensure_signed(origin)?;786 Self::collection_exists(collection_id)?;787 let target_collection = <Collection<T>>::get(collection_id);788789 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {790 ensure!(target_collection.mint_mode == true, "Public minting is not allowed for this collection");791 Self::check_white_list(collection_id, &owner)?;792 Self::check_white_list(collection_id, &sender)?;793 }794795 match target_collection.mode796 {797 CollectionMode::NFT(_) => {798799 // check size800 ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");801802 // Create nft item803 let item = NftItemType {804 collection: collection_id,805 owner: owner,806 data: properties.clone(),807 };808809 Self::add_nft_item(item)?;810811 },812 CollectionMode::Fungible(_) => {813814 // check size815 ensure!(properties.len() as u32 == 0, "Size of item must be 0 with fungible type");816817 let item = FungibleItemType {818 collection: collection_id,819 owner: owner,820 value: (10 as u128).pow(target_collection.decimal_points)821 };822823 Self::add_fungible_item(item)?;824 },825 CollectionMode::ReFungible(_, _) => {826827 // check size828 ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");829830 let mut owner_list = Vec::new();831 let value = (10 as u128).pow(target_collection.decimal_points);832 owner_list.push(Ownership {owner: owner.clone(), fraction: value});833834 let item = ReFungibleItemType {835 collection: collection_id,836 owner: owner_list,837 data: properties.clone()838 };839840 Self::add_refungible_item(item)?;841 },842 _ => { ensure!(1 == 0,"just error"); }843844 };845846 // call event847 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));848849 Ok(())850 }851852 /// Destroys a concrete instance of NFT.853 /// 854 /// # Permissions855 /// 856 /// * Collection Owner.857 /// * Collection Admin.858 /// * Current NFT Owner.859 /// 860 /// # Arguments861 /// 862 /// * collection_id: ID of the collection.863 /// 864 /// * item_id: ID of NFT to burn.865 #[weight = T::WeightInfo::burn_item()]866 pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {867868 let sender = ensure_signed(origin)?;869 Self::collection_exists(collection_id)?;870871 // Transfer permissions check872 let target_collection = <Collection<T>>::get(collection_id);873 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||874 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),875 "Only item owner, collection owner and admins can modify item");876877 if target_collection.access == AccessMode::WhiteList {878 Self::check_white_list(collection_id, &sender)?;879 }880881 match target_collection.mode882 {883 CollectionMode::NFT(_) => Self::burn_nft_item(collection_id, item_id)?,884 CollectionMode::Fungible(_) => Self::burn_fungible_item(collection_id, item_id)?,885 CollectionMode::ReFungible(_, _) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,886 _ => ()887 };888889 // call event890 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));891892 Ok(())893 }894895 /// Change ownership of the token.896 /// 897 /// # Permissions898 /// 899 /// * Collection Owner900 /// * Collection Admin901 /// * Current NFT owner902 ///903 /// # Arguments904 /// 905 /// * recipient: Address of token recipient.906 /// 907 /// * collection_id.908 /// 909 /// * item_id: ID of the item910 /// * Non-Fungible Mode: Required.911 /// * Fungible Mode: Ignored.912 /// * Re-Fungible Mode: Required.913 /// 914 /// * value: Amount to transfer.915 /// * Non-Fungible Mode: Ignored916 /// * Fungible Mode: Must specify transferred amount917 /// * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)918 #[weight = T::WeightInfo::transfer()]919 pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {920921 let sender = ensure_signed(origin)?;922923 // Transfer permissions check924 let target_collection = <Collection<T>>::get(collection_id);925 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||926 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),927 "Only item owner, collection owner and admins can modify item");928929 if target_collection.access == AccessMode::WhiteList {930 Self::check_white_list(collection_id, &sender)?;931 Self::check_white_list(collection_id, &recipient)?;932 }933934 match target_collection.mode935 {936 CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,937 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,938 CollectionMode::ReFungible(_, _) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,939 _ => ()940 };941942 Ok(())943 }944945 /// Set, change, or remove approved address to transfer the ownership of the NFT.946 /// 947 /// # Permissions948 /// 949 /// * Collection Owner950 /// * Collection Admin951 /// * Current NFT owner952 /// 953 /// # Arguments954 /// 955 /// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).956 /// 957 /// * collection_id.958 /// 959 /// * item_id: ID of the item.960 #[weight = T::WeightInfo::approve()]961 pub fn approve(origin, approved: T::AccountId, collection_id: u64, item_id: u64) -> DispatchResult {962963 let sender = ensure_signed(origin)?;964965 // Transfer permissions check966 let target_collection = <Collection<T>>::get(collection_id);967 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||968 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),969 "Only item owner, collection owner and admins can approve");970971 if target_collection.access == AccessMode::WhiteList {972 Self::check_white_list(collection_id, &sender)?;973 Self::check_white_list(collection_id, &approved)?;974 }975976 // amount param stub977 let amount = 100000000;978979 let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));980 if list_exists {981982 let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));983 let item_contains = list.iter().any(|i| i.approved == approved);984985 if !item_contains {986 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });987 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);988 }989 } else {990991 let mut list = Vec::new();992 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });993 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);994 }995996 Ok(())997 }998 999 /// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.1000 /// 1001 /// # Permissions1002 /// * Collection Owner1003 /// * Collection Admin1004 /// * Current NFT owner1005 /// * Address approved by current NFT owner1006 /// 1007 /// # Arguments1008 /// 1009 /// * from: Address that owns token.1010 /// 1011 /// * recipient: Address of token recipient.1012 /// 1013 /// * collection_id.1014 /// 1015 /// * item_id: ID of the item.1016 /// 1017 /// * value: Amount to transfer.1018 #[weight = T::WeightInfo::transfer_from()]1019 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64 ) -> DispatchResult {10201021 let sender = ensure_signed(origin)?;1022 let mut appoved_transfer = false;10231024 // Check approve1025 if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {1026 let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));1027 let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());1028 if opt_item.is_some()1029 {1030 appoved_transfer = true;1031 ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");1032 }1033 }10341035 // Transfer permissions check1036 let target_collection = <Collection<T>>::get(collection_id);1037 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1038 "Only item owner, collection owner and admins can modify items");10391040 if target_collection.access == AccessMode::WhiteList {1041 Self::check_white_list(collection_id, &sender)?;1042 Self::check_white_list(collection_id, &recipient)?;1043 }10441045 // remove approve1046 let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))1047 .into_iter().filter(|i| i.approved != sender.clone()).collect();1048 <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);104910501051 match target_collection.mode1052 {1053 CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, from, recipient)?,1054 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1055 CollectionMode::ReFungible(_, _) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1056 _ => ()1057 };10581059 Ok(())1060 }10611062 ///1063 #[weight = 0]1064 pub fn safe_transfer_from(origin, collection_id: u64, item_id: u64, new_owner: T::AccountId) -> DispatchResult {10651066 // let no_perm_mes = "You do not have permissions to modify this collection";1067 // ensure!(<ApprovedList<T>>::contains_key((collection_id, item_id)), no_perm_mes);1068 // let list_itm = <ApprovedList<T>>::get((collection_id, item_id));1069 // ensure!(list_itm.contains(&new_owner.clone()), no_perm_mes);10701071 // // on_nft_received call10721073 // Self::transfer(origin, collection_id, item_id, new_owner)?;10741075 Ok(())1076 }10771078 /// Set off-chain data schema.1079 /// 1080 /// # Permissions1081 /// 1082 /// * Collection Owner1083 /// * Collection Admin1084 /// 1085 /// # Arguments1086 /// 1087 /// * collection_id.1088 /// 1089 /// * schema: String representing the offchain data schema.1090 #[weight = T::WeightInfo::set_offchain_schema()]1091 pub fn set_offchain_schema(1092 origin,1093 collection_id: u64,1094 schema: Vec<u8>1095 ) -> DispatchResult {1096 let sender = ensure_signed(origin)?;1097 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;10981099 let mut target_collection = <Collection<T>>::get(collection_id);1100 target_collection.offchain_schema = schema;1101 <Collection<T>>::insert(collection_id, target_collection);11021103 Ok(())1104 }11051106 // Sudo permissions function1107 #[weight = 0]1108 pub fn set_chain_limits(1109 origin,1110 limits: ChainLimits1111 ) -> DispatchResult {1112 ensure_root(origin)?;1113 <ChainLimit>::put(limits);1114 Ok(())1115 } 1116 }1117}11181119impl<T: Trait> Module<T> {1120 fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1121 let current_index = <ItemListIndex>::get(item.collection)1122 .checked_add(1)1123 .expect("Item list index id error");1124 let itemcopy = item.clone();1125 let owner = item.owner.clone();1126 let value = item.value as u64;11271128 Self::add_token_index(item.collection, current_index, owner.clone())?;11291130 <ItemListIndex>::insert(item.collection, current_index);1131 <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);11321133 // Add current block1134 let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1135 <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);1136 1137 // Update balance1138 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1139 .checked_add(value)1140 .unwrap();1141 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);11421143 Ok(())1144 }11451146 fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1147 let current_index = <ItemListIndex>::get(item.collection)1148 .checked_add(1)1149 .expect("Item list index id error");1150 let itemcopy = item.clone();11511152 let value = item.owner.first().unwrap().fraction as u64;1153 let owner = item.owner.first().unwrap().owner.clone();11541155 Self::add_token_index(item.collection, current_index, owner.clone())?;11561157 <ItemListIndex>::insert(item.collection, current_index);1158 <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);11591160 // Add current block1161 let block_number: T::BlockNumber = 0.into();1162 <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);11631164 // Update balance1165 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1166 .checked_add(value)1167 .unwrap();1168 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);11691170 Ok(())1171 }11721173 fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {1174 let current_index = <ItemListIndex>::get(item.collection)1175 .checked_add(1)1176 .expect("Item list index id error");11771178 let item_owner = item.owner.clone();1179 let collection_id = item.collection.clone();1180 Self::add_token_index(collection_id, current_index, item.owner.clone())?;11811182 <ItemListIndex>::insert(collection_id, current_index);1183 <NftItemList<T>>::insert(collection_id, current_index, item);11841185 // Add current block1186 let block_number: T::BlockNumber = 0.into();1187 <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);11881189 // Update balance1190 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1191 .checked_add(1)1192 .unwrap();1193 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);11941195 Ok(())1196 }11971198 fn burn_refungible_item(1199 collection_id: u64,1200 item_id: u64,1201 owner: T::AccountId,1202 ) -> DispatchResult {1203 ensure!(1204 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1205 "Item does not exists"1206 );1207 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1208 let item = collection1209 .owner1210 .iter()1211 .filter(|&i| i.owner == owner)1212 .next()1213 .unwrap();1214 Self::remove_token_index(collection_id, item_id, owner.clone())?;12151216 // remove approve list1217 <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));12181219 // update balance1220 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1221 .checked_sub(item.fraction as u64)1222 .unwrap();1223 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);12241225 <ReFungibleItemList<T>>::remove(collection_id, item_id);12261227 Ok(())1228 }12291230 fn burn_nft_item(collection_id: u64, item_id: u64) -> DispatchResult {1231 ensure!(1232 <NftItemList<T>>::contains_key(collection_id, item_id),1233 "Item does not exists"1234 );1235 let item = <NftItemList<T>>::get(collection_id, item_id);1236 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;12371238 // remove approve list1239 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));12401241 // update balance1242 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1243 .checked_sub(1)1244 .unwrap();1245 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1246 <NftItemList<T>>::remove(collection_id, item_id);12471248 Ok(())1249 }12501251 fn burn_fungible_item(collection_id: u64, item_id: u64) -> DispatchResult {1252 ensure!(1253 <FungibleItemList<T>>::contains_key(collection_id, item_id),1254 "Item does not exists"1255 );1256 let item = <FungibleItemList<T>>::get(collection_id, item_id);1257 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;12581259 // remove approve list1260 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));12611262 // update balance1263 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1264 .checked_sub(item.value as u64)1265 .unwrap();1266 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);12671268 <FungibleItemList<T>>::remove(collection_id, item_id);12691270 Ok(())1271 }12721273 fn collection_exists(collection_id: u64) -> DispatchResult {1274 ensure!(1275 <Collection<T>>::contains_key(collection_id),1276 "This collection does not exist"1277 );1278 Ok(())1279 }12801281 fn check_owner_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult {1282 Self::collection_exists(collection_id)?;12831284 let target_collection = <Collection<T>>::get(collection_id);1285 ensure!(1286 subject == target_collection.owner,1287 "You do not own this collection"1288 );12891290 Ok(())1291 }12921293 fn is_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> bool {1294 let target_collection = <Collection<T>>::get(collection_id);1295 let mut result: bool = subject == target_collection.owner;1296 let exists = <AdminList<T>>::contains_key(collection_id);12971298 if !result & exists {1299 if <AdminList<T>>::get(collection_id).contains(&subject) {1300 result = true1301 }1302 }13031304 result1305 }13061307 fn check_owner_or_admin_permissions(1308 collection_id: u64,1309 subject: T::AccountId,1310 ) -> DispatchResult {1311 Self::collection_exists(collection_id)?;1312 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());13131314 ensure!(1315 result,1316 "You do not have permissions to modify this collection"1317 );1318 Ok(())1319 }13201321 fn is_item_owner(subject: T::AccountId, collection_id: u64, item_id: u64) -> bool {1322 let target_collection = <Collection<T>>::get(collection_id);13231324 match target_collection.mode {1325 CollectionMode::NFT(_) => {1326 <NftItemList<T>>::get(collection_id, item_id).owner == subject1327 }1328 CollectionMode::Fungible(_) => {1329 <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1330 }1331 CollectionMode::ReFungible(_, _) => {1332 <ReFungibleItemList<T>>::get(collection_id, item_id)1333 .owner1334 .iter()1335 .any(|i| i.owner == subject)1336 }1337 CollectionMode::Invalid => false,1338 }1339 }13401341 fn check_white_list(collection_id: u64, address: &T::AccountId) -> DispatchResult {1342 let mes = "Address is not in white list";1343 ensure!(<WhiteList<T>>::contains_key(collection_id), mes);1344 let wl = <WhiteList<T>>::get(collection_id);1345 ensure!(wl.contains(address), mes);13461347 Ok(())1348 }13491350 fn transfer_fungible(1351 collection_id: u64,1352 item_id: u64,1353 value: u64,1354 owner: T::AccountId,1355 new_owner: T::AccountId,1356 ) -> DispatchResult {1357 ensure!(1358 <FungibleItemList<T>>::contains_key(collection_id, item_id),1359 "Item not exists"1360 );13611362 let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1363 let amount = full_item.value;13641365 ensure!(amount >= value.into(), "Item balance not enouth");13661367 // update balance1368 let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1369 .checked_sub(value)1370 .unwrap();1371 <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);13721373 let mut new_owner_account_id = 0;1374 let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1375 if new_owner_items.len() > 0 {1376 new_owner_account_id = new_owner_items[0];1377 }13781379 let val64 = value.into();13801381 // transfer1382 if amount == val64 && new_owner_account_id == 0 {1383 // change owner1384 // new owner do not have account1385 let mut new_full_item = full_item.clone();1386 new_full_item.owner = new_owner.clone();1387 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);13881389 // update balance1390 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1391 .checked_add(value)1392 .unwrap();1393 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);13941395 // update index collection1396 Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1397 } else {1398 let mut new_full_item = full_item.clone();1399 new_full_item.value -= val64;14001401 // separate amount1402 if new_owner_account_id > 0 {1403 // new owner has account1404 let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1405 item.value += val64;14061407 // update balance1408 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1409 .checked_add(value)1410 .unwrap();1411 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);14121413 <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1414 } else {1415 // new owner do not have account1416 let item = FungibleItemType {1417 collection: collection_id,1418 owner: new_owner.clone(),1419 value: val64,1420 };14211422 Self::add_fungible_item(item)?;1423 }14241425 if amount == val64 {1426 Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;14271428 // remove approve list1429 <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1430 <FungibleItemList<T>>::remove(collection_id, item_id);1431 }14321433 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1434 }14351436 Ok(())1437 }14381439 fn transfer_refungible(1440 collection_id: u64,1441 item_id: u64,1442 value: u64,1443 owner: T::AccountId,1444 new_owner: T::AccountId,1445 ) -> DispatchResult {1446 ensure!(1447 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1448 "Item not exists"1449 );14501451 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1452 let item = full_item1453 .owner1454 .iter()1455 .filter(|i| i.owner == owner)1456 .next()1457 .unwrap();1458 let amount = item.fraction;14591460 ensure!(amount >= value.into(), "Item balance not enouth");14611462 // update balance1463 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1464 .checked_sub(value)1465 .unwrap();1466 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);14671468 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1469 .checked_add(value)1470 .unwrap();1471 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);14721473 let old_owner = item.owner.clone();1474 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);1475 let val64 = value.into();14761477 // transfer1478 if amount == val64 && !new_owner_has_account {1479 // change owner1480 // new owner do not have account1481 let mut new_full_item = full_item.clone();1482 new_full_item1483 .owner1484 .iter_mut()1485 .find(|i| i.owner == owner)1486 .unwrap()1487 .owner = new_owner.clone();1488 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);14891490 // update index collection1491 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1492 } else {1493 let mut new_full_item = full_item.clone();1494 new_full_item1495 .owner1496 .iter_mut()1497 .find(|i| i.owner == owner)1498 .unwrap()1499 .fraction -= val64;15001501 // separate amount1502 if new_owner_has_account {1503 // new owner has account1504 new_full_item1505 .owner1506 .iter_mut()1507 .find(|i| i.owner == new_owner)1508 .unwrap()1509 .fraction += val64;1510 } else {1511 // new owner do not have account1512 new_full_item.owner.push(Ownership {1513 owner: new_owner.clone(),1514 fraction: val64,1515 });1516 Self::add_token_index(collection_id, item_id, new_owner.clone())?;1517 }15181519 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1520 }15211522 Ok(())1523 }15241525 fn transfer_nft(1526 collection_id: u64,1527 item_id: u64,1528 sender: T::AccountId,1529 new_owner: T::AccountId,1530 ) -> DispatchResult {1531 ensure!(1532 <NftItemList<T>>::contains_key(collection_id, item_id),1533 "Item not exists"1534 );15351536 let mut item = <NftItemList<T>>::get(collection_id, item_id);15371538 ensure!(1539 sender == item.owner,1540 "sender parameter and item owner must be equal"1541 );15421543 // update balance1544 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1545 .checked_sub(1)1546 .unwrap();1547 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);15481549 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1550 .checked_add(1)1551 .unwrap();1552 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);15531554 // change owner1555 let old_owner = item.owner.clone();1556 item.owner = new_owner.clone();1557 <NftItemList<T>>::insert(collection_id, item_id, item);15581559 // update index collection1560 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;15611562 // reset approved list1563 <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));1564 Ok(())1565 }15661567 fn init_collection(item: &CollectionType<T::AccountId>) {1568 // check params1569 assert!(1570 item.decimal_points <= 4,1571 "decimal_points parameter must be lower than 4"1572 );1573 assert!(1574 item.name.len() <= 64,1575 "Collection name can not be longer than 63 char"1576 );1577 assert!(1578 item.name.len() <= 256,1579 "Collection description can not be longer than 255 char"1580 );1581 assert!(1582 item.token_prefix.len() <= 16,1583 "Token prefix can not be longer than 15 char"1584 );15851586 // Generate next collection ID1587 let next_id = CreatedCollectionCount::get()1588 .checked_add(1)1589 .expect("collection id error");15901591 CreatedCollectionCount::put(next_id);1592 }15931594 fn init_nft_token(item: &NftItemType<T::AccountId>) {1595 let current_index = <ItemListIndex>::get(item.collection)1596 .checked_add(1)1597 .expect("Item list index id error");15981599 let item_owner = item.owner.clone();1600 let collection_id = item.collection.clone();1601 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();16021603 <ItemListIndex>::insert(collection_id, current_index);16041605 // Update balance1606 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1607 .checked_add(1)1608 .unwrap();1609 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);1610 }16111612 fn init_fungible_token(item: &FungibleItemType<T::AccountId>) {1613 let current_index = <ItemListIndex>::get(item.collection)1614 .checked_add(1)1615 .expect("Item list index id error");1616 let owner = item.owner.clone();1617 let value = item.value as u64;16181619 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();16201621 <ItemListIndex>::insert(item.collection, current_index);16221623 // Update balance1624 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1625 .checked_add(value)1626 .unwrap();1627 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1628 }16291630 fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {1631 let current_index = <ItemListIndex>::get(item.collection)1632 .checked_add(1)1633 .expect("Item list index id error");16341635 let value = item.owner.first().unwrap().fraction as u64;1636 let owner = item.owner.first().unwrap().owner.clone();16371638 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();16391640 <ItemListIndex>::insert(item.collection, current_index);16411642 // Update balance1643 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1644 .checked_add(value)1645 .unwrap();1646 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1647 }16481649 fn add_token_index(collection_id: u64, item_index: u64, owner: T::AccountId) -> DispatchResult {16501651 // add to account limit1652 if <AccountItemCount<T>>::contains_key(owner.clone()) {16531654 // bound Owned tokens by a single address1655 let count = <AccountItemCount<T>>::get(owner.clone());1656 ensure!(count < ChainLimit::get().account_token_ownership_limit, "Owned tokens by a single address bound exceeded");16571658 <AccountItemCount<T>>::insert(owner.clone(), 1659 count.checked_add(1).unwrap());1660 }1661 else {1662 <AccountItemCount<T>>::insert(owner.clone(), 1);1663 }16641665 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1666 if list_exists {1667 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1668 let item_contains = list.contains(&item_index.clone());16691670 if !item_contains {1671 list.push(item_index.clone());1672 }16731674 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);1675 } else {1676 let mut itm = Vec::new();1677 itm.push(item_index.clone());1678 <AddressTokens<T>>::insert(collection_id, owner, itm);1679 1680 }16811682 Ok(())1683 }16841685 fn remove_token_index(1686 collection_id: u64,1687 item_index: u64,1688 owner: T::AccountId,1689 ) -> DispatchResult {16901691 // update counter1692 <AccountItemCount<T>>::insert(owner.clone(), 1693 <AccountItemCount<T>>::get(owner.clone()).checked_sub(1).unwrap());169416951696 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1697 if list_exists {1698 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1699 let item_contains = list.contains(&item_index.clone());17001701 if item_contains {1702 list.retain(|&item| item != item_index);1703 <AddressTokens<T>>::insert(collection_id, owner, list);1704 }1705 }17061707 Ok(())1708 }17091710 fn move_token_index(1711 collection_id: u64,1712 item_index: u64,1713 old_owner: T::AccountId,1714 new_owner: T::AccountId,1715 ) -> DispatchResult {1716 Self::remove_token_index(collection_id, item_index, old_owner)?;1717 Self::add_token_index(collection_id, item_index, new_owner)?;17181719 Ok(())1720 }1721}17221723////////////////////////////////////////////////////////////////////////////////////////////////////1724// Economic models1725// #region17261727/// Fee multiplier.1728pub type Multiplier = FixedU128;17291730type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1731 <T as system::Trait>::AccountId,1732>>::Balance;1733type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1734 <T as system::Trait>::AccountId,1735>>::NegativeImbalance;17361737/// Require the transactor pay for themselves and maybe include a tip to gain additional priority1738/// in the queue.1739#[derive(Encode, Decode, Clone, Eq, PartialEq)]1740pub struct ChargeTransactionPayment<T: transaction_payment::Trait + Send + Sync>(1741 #[codec(compact)] BalanceOf<T>,1742);17431744impl<T: Trait + transaction_payment::Trait + Send + Sync> sp_std::fmt::Debug1745 for ChargeTransactionPayment<T>1746{1747 #[cfg(feature = "std")]1748 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1749 write!(f, "ChargeTransactionPayment<{:?}>", self.0)1750 }1751 #[cfg(not(feature = "std"))]1752 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1753 Ok(())1754 }1755}17561757impl<T: Trait + transaction_payment::Trait + Send + Sync> ChargeTransactionPayment<T>1758where1759 T::Call:1760 Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>>,1761 BalanceOf<T>: Send + Sync + FixedPointOperand,1762{1763 /// utility constructor. Used only in client/factory code.1764 pub fn from(fee: BalanceOf<T>) -> Self {1765 Self(fee)1766 }17671768 pub fn traditional_fee(1769 len: usize,1770 info: &DispatchInfoOf<T::Call>,1771 tip: BalanceOf<T>,1772 ) -> BalanceOf<T>1773 where1774 T::Call: Dispatchable<Info = DispatchInfo>,1775 {1776 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)1777 }17781779 fn withdraw_fee(1780 &self,1781 who: &T::AccountId,1782 call: &T::Call,1783 info: &DispatchInfoOf<T::Call>,1784 len: usize,1785 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {1786 let tip = self.0;17871788 // Set fee based on call type. Creating collection costs 1 Unique.1789 // All other transactions have traditional fees so far1790 let fee = match call.is_sub_type() {1791 Some(Call::create_collection(..)) => <BalanceOf<T>>::from(1_000_000_000),1792 _ => Self::traditional_fee(len, info, tip), // Flat fee model, use only for testing purposes1793 // _ => <BalanceOf<T>>::from(100)1794 };17951796 // Determine who is paying transaction fee based on ecnomic model1797 // Parse call to extract collection ID and access collection sponsor1798 let sponsor: T::AccountId = match call.is_sub_type() {1799 Some(Call::create_item(collection_id, _properties, _owner)) => {1800 <Collection<T>>::get(collection_id).sponsor1801 }1802 Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {1803 let _collection_mode = <Collection<T>>::get(collection_id).mode;18041805 // sponsor timeout1806 let sponsor_transfer = match _collection_mode {1807 CollectionMode::NFT(_) => {1808 let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);1809 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1810 let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();1811 if block_number >= limit_time {1812 <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);1813 true1814 }1815 else {1816 false1817 }1818 }1819 CollectionMode::Fungible(_) => {1820 let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);1821 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1822 if basket.iter().any(|i| i.address == _new_owner.clone())1823 {1824 let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();1825 let limit_time = item.start_block + ChainLimit::get().fungible_sponsor_transfer_timeout.into();1826 if block_number >= limit_time {1827 basket.retain(|x| x.address == item.address);1828 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });1829 <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);1830 true1831 }1832 else {1833 false1834 }1835 }1836 else {1837 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});1838 true1839 }1840 }1841 CollectionMode::ReFungible(_, _) => {1842 let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);1843 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1844 let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();1845 if block_number >= limit_time {1846 <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);1847 true1848 } else {1849 false1850 }1851 }1852 _ => {1853 false1854 },1855 };18561857 if !sponsor_transfer {1858 T::AccountId::default()1859 } else {1860 <Collection<T>>::get(collection_id).sponsor1861 }1862 }18631864 _ => T::AccountId::default(),1865 };18661867 let mut who_pays_fee: T::AccountId = sponsor.clone();1868 if sponsor == T::AccountId::default() {1869 who_pays_fee = who.clone();1870 }18711872 // Only mess with balances if fee is not zero.1873 if fee.is_zero() {1874 return Ok((fee, None));1875 }18761877 match <T as transaction_payment::Trait>::Currency::withdraw(1878 &who_pays_fee,1879 fee,1880 if tip.is_zero() {1881 WithdrawReason::TransactionPayment.into()1882 } else {1883 WithdrawReason::TransactionPayment | WithdrawReason::Tip1884 },1885 ExistenceRequirement::KeepAlive,1886 ) {1887 Ok(imbalance) => Ok((fee, Some(imbalance))),1888 Err(_) => Err(InvalidTransaction::Payment.into()),1889 }1890 }1891}18921893impl<T: Trait + transaction_payment::Trait + Send + Sync> SignedExtension1894 for ChargeTransactionPayment<T>1895where1896 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,1897 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>>,1898{1899 const IDENTIFIER: &'static str = "ChargeTransactionPayment";1900 type AccountId = T::AccountId;1901 type Call = T::Call;1902 type AdditionalSigned = ();1903 type Pre = (1904 BalanceOf<T>,1905 Self::AccountId,1906 Option<NegativeImbalanceOf<T>>,1907 BalanceOf<T>,1908 );1909 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {1910 Ok(())1911 }19121913 fn validate(1914 &self,1915 who: &Self::AccountId,1916 call: &Self::Call,1917 info: &DispatchInfoOf<Self::Call>,1918 len: usize,1919 ) -> TransactionValidity {1920 let (fee, _) = self.withdraw_fee(who, call, info, len)?;19211922 let mut r = ValidTransaction::default();1923 // NOTE: we probably want to maximize the _fee (of any type) per weight unit_ here, which1924 // will be a bit more than setting the priority to tip. For now, this is enough.1925 r.priority = fee.saturated_into::<TransactionPriority>();1926 Ok(r)1927 }19281929 fn pre_dispatch(1930 self,1931 who: &Self::AccountId,1932 call: &Self::Call,1933 info: &DispatchInfoOf<Self::Call>,1934 len: usize,1935 ) -> Result<Self::Pre, TransactionValidityError> {1936 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;1937 Ok((self.0, who.clone(), imbalance, fee))1938 }19391940 fn post_dispatch(1941 pre: Self::Pre,1942 info: &DispatchInfoOf<Self::Call>,1943 post_info: &PostDispatchInfoOf<Self::Call>,1944 len: usize,1945 _result: &DispatchResult,1946 ) -> Result<(), TransactionValidityError> {1947 let (tip, who, imbalance, fee) = pre;1948 if let Some(payed) = imbalance {1949 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(1950 len as u32, info, post_info, tip,1951 );1952 let refund = fee.saturating_sub(actual_fee);1953 let actual_payment =1954 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(1955 &who, refund,1956 ) {1957 Ok(refund_imbalance) => {1958 // The refund cannot be larger than the up front payed max weight.1959 // `PostDispatchInfo::calc_unspent` guards against such a case.1960 match payed.offset(refund_imbalance) {1961 Ok(actual_payment) => actual_payment,1962 Err(_) => return Err(InvalidTransaction::Payment.into()),1963 }1964 }1965 // We do not recreate the account using the refund. The up front payment1966 // is gone in that case.1967 Err(_) => payed,1968 };1969 let imbalances = actual_payment.split(tip);1970 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(1971 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),1972 );1973 }1974 Ok(())1975 }1976}1977// #endregion197819791#![cfg_attr(not(feature = "std"), no_std)]23#[cfg(feature = "std")]4pub use std::*;56#[cfg(feature = "std")]7pub use serde::*;89use codec::{Decode, Encode};10pub use frame_support::{11 construct_runtime, decl_event, decl_module, decl_storage,12 dispatch::DispatchResult,13 ensure, parameter_types, fail,14 traits::{15 Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,16 Randomness, WithdrawReason,17 },18 weights::{19 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},20 DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,21 WeightToFeePolynomial,22 },23 IsSubType, StorageValue,24};25// use frame_support::weights::{Weight, constants::RocksDbWeight as DbWeight};2627use frame_system::{self as system, ensure_signed, ensure_root};28use sp_runtime::sp_std::prelude::Vec;29use sp_runtime::{30 traits::{31 DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SaturatedConversion, Saturating,32 SignedExtension, Zero,33 },34 transaction_validity::{35 InvalidTransaction, TransactionPriority, TransactionValidity, TransactionValidityError,36 ValidTransaction,37 },38 FixedPointOperand, FixedU128,39};4041#[cfg(test)]42mod mock;4344#[cfg(test)]45mod tests;4647mod default_weights;4849// Structs50// #region5152#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]53#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]54pub enum CollectionMode {55 Invalid,56 NFT,57 // decimal points58 Fungible(u32),59 // decimal points60 ReFungible(u32),61}6263impl Into<u8> for CollectionMode {64 fn into(self) -> u8 {65 match self {66 CollectionMode::Invalid => 0,67 CollectionMode::NFT => 1,68 CollectionMode::Fungible(_) => 2,69 CollectionMode::ReFungible(_) => 3,70 }71 }72}7374#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]75#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]76pub enum AccessMode {77 Normal,78 WhiteList,79}80impl Default for AccessMode {81 fn default() -> Self {82 Self::Normal83 }84}8586impl Default for CollectionMode {87 fn default() -> Self {88 Self::Invalid89 }90}9192#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]93#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]94pub struct Ownership<AccountId> {95 pub owner: AccountId,96 pub fraction: u128,97}9899#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]100#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]101pub struct CollectionType<AccountId> {102 pub owner: AccountId,103 pub mode: CollectionMode,104 pub access: AccessMode,105 pub decimal_points: u32,106 pub name: Vec<u16>, // 64 include null escape char107 pub description: Vec<u16>, // 256 include null escape char108 pub token_prefix: Vec<u8>, // 16 include null escape char109 pub mint_mode: bool,110 pub offchain_schema: Vec<u8>,111 pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender112 pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship113 pub variable_on_chain_schema: Vec<u8>, //114 pub const_on_chain_schema: Vec<u8>, //115}116117#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]118#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]119pub struct CollectionAdminsType<AccountId> {120 pub admin: AccountId,121 pub collection_id: u64,122}123124#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]125#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]126pub struct NftItemType<AccountId> {127 pub collection: u64,128 pub owner: AccountId,129 pub const_data: Vec<u8>,130 pub variable_data: Vec<u8>,131}132133#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]134#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]135pub struct FungibleItemType<AccountId> {136 pub collection: u64,137 pub owner: AccountId,138 pub value: u128,139}140141#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]142#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]143pub struct ReFungibleItemType<AccountId> {144 pub collection: u64,145 pub owner: Vec<Ownership<AccountId>>,146 pub const_data: Vec<u8>,147 pub variable_data: Vec<u8>,148}149150#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]151#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]152pub struct ApprovePermissions<AccountId> {153 pub approved: AccountId,154 pub amount: u64,155}156157#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]158#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]159pub struct VestingItem<AccountId, Moment> {160 pub sender: AccountId,161 pub recipient: AccountId,162 pub collection_id: u64,163 pub item_id: u64,164 pub amount: u64,165 pub vesting_date: Moment,166}167168#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]169#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]170pub struct BasketItem<AccountId, BlockNumber> {171 pub address: AccountId,172 pub start_block: BlockNumber,173}174175#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]176#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]177pub struct ChainLimits {178 pub collection_numbers_limit: u64,179 pub account_token_ownership_limit: u64,180 pub collections_admins_limit: u64,181 pub custom_data_limit: u32,182183 // Timeouts for item types in passed blocks184 pub nft_sponsor_transfer_timeout: u32,185 pub fungible_sponsor_transfer_timeout: u32,186 pub refungible_sponsor_transfer_timeout: u32,187}188189pub trait WeightInfo {190 fn create_collection() -> Weight;191 fn destroy_collection() -> Weight;192 fn add_to_white_list() -> Weight;193 fn remove_from_white_list() -> Weight;194 fn set_public_access_mode() -> Weight;195 fn set_mint_permission() -> Weight;196 fn change_collection_owner() -> Weight;197 fn add_collection_admin() -> Weight;198 fn remove_collection_admin() -> Weight;199 fn set_collection_sponsor() -> Weight;200 fn confirm_sponsorship() -> Weight;201 fn remove_collection_sponsor() -> Weight;202 fn create_item(s: usize) -> Weight;203 fn burn_item() -> Weight;204 fn transfer() -> Weight;205 fn approve() -> Weight;206 fn transfer_from() -> Weight;207 fn set_offchain_schema() -> Weight;208 fn set_const_on_chain_schema() -> Weight;209 fn set_variable_on_chain_schema() -> Weight;210 fn set_variable_meta_data() -> Weight;211}212213#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]214#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]215pub struct CreateNftData {216 pub const_data: Vec<u8>,217 pub variable_data: Vec<u8>,218}219220#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]221#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]222pub struct CreateFungibleData {223}224225#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]226#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]227pub struct CreateReFungibleData {228 pub const_data: Vec<u8>,229 pub variable_data: Vec<u8>,230}231232#[derive(Encode, Decode, Debug, Clone, PartialEq)]233#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]234pub enum CreateItemData {235 NFT(CreateNftData),236 Fungible(CreateFungibleData),237 ReFungible(CreateReFungibleData)238}239240impl CreateItemData {241 pub fn len(&self) -> usize {242 let len = match self {243 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),244 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),245 _ => 0246 };247 248 return len;249 }250}251252pub trait Trait: system::Trait + Sized {253 type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;254255 /// Weight information for extrinsics in this pallet.256 type WeightInfo: WeightInfo;257}258259#[cfg(feature = "runtime-benchmarks")]260mod benchmarking;261262// #endregion263264decl_storage! {265 trait Store for Module<T: Trait> as Nft {266267 // Private members268 NextCollectionID: u64;269 CreatedCollectionCount: u64;270 ChainVersion: u64;271 ItemListIndex: map hasher(blake2_128_concat) u64 => u64;272273 // Chain limits struct274 pub ChainLimit get(fn chain_limit) config(): ChainLimits;275276 // Bound counters277 CollectionCount: u64;278 pub AccountItemCount get(fn account_item_count): map hasher(identity) T::AccountId => u64;279280 // Basic collections281 pub Collection get(fn collection) config(): map hasher(identity) u64 => CollectionType<T::AccountId>;282 pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec<T::AccountId>;283 pub WhiteList get(fn white_list): map hasher(identity) u64 => Vec<T::AccountId>;284285 /// Balance owner per collection map286 pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => u64;287288 /// second parameter: item id + owner account id289 pub ApprovedList get(fn approved): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) (u64, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;290291 /// Item collections292 pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;293 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;294 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;295296 /// Index list297 pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;298299 /// Tokens transfer baskets300 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;301 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => Vec<BasketItem<T::AccountId, T::BlockNumber>>;302 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;303304 // Sponsorship305 pub ContractSponsor get(fn contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;306 pub UnconfirmedContractSponsor get(fn unconfirmed_contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;307 }308 add_extra_genesis {309 build(|config: &GenesisConfig<T>| {310 // Modification of storage311 for (_num, _c) in &config.collection {312 <Module<T>>::init_collection(_c);313 }314315 for (_num, _q, _i) in &config.nft_item_id {316 <Module<T>>::init_nft_token(_i);317 }318319 for (_num, _q, _i) in &config.fungible_item_id {320 <Module<T>>::init_fungible_token(_i);321 }322323 for (_num, _q, _i) in &config.refungible_item_id {324 <Module<T>>::init_refungible_token(_i);325 }326 })327 }328}329330decl_event!(331 pub enum Event<T>332 where333 AccountId = <T as system::Trait>::AccountId,334 {335 /// New collection was created336 /// 337 /// # Arguments338 /// 339 /// * collection_id: Globally unique identifier of newly created collection.340 /// 341 /// * mode: [CollectionMode] converted into u8.342 /// 343 /// * account_id: Collection owner.344 Created(u64, u8, AccountId),345346 /// New item was created.347 /// 348 /// # Arguments349 /// 350 /// * collection_id: Id of the collection where item was created.351 /// 352 /// * item_id: Id of an item. Unique within the collection.353 ItemCreated(u64, u64),354355 /// Collection item was burned.356 /// 357 /// # Arguments358 /// 359 /// collection_id.360 /// 361 /// item_id: Identifier of burned NFT.362 ItemDestroyed(u64, u64),363 }364);365366decl_module! {367 pub struct Module<T: Trait> for enum Call where origin: T::Origin {368369 fn deposit_event() = default;370371 fn on_initialize(now: T::BlockNumber) -> Weight {372373 if ChainVersion::get() < 2374 {375 let value = NextCollectionID::get();376 CreatedCollectionCount::put(value);377 ChainVersion::put(2);378 }379380 0381 }382383 /// This method creates a Collection of NFTs. Each Token may have multiple properties encoded as an array of bytes of certain length. The initial owner and admin of the collection are set to the address that signed the transaction. Both addresses can be changed later.384 /// 385 /// # Permissions386 /// 387 /// * Anyone.388 /// 389 /// # Arguments390 /// 391 /// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.392 /// 393 /// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.394 /// 395 /// * token_prefix: UTF-8 string with token prefix.396 /// 397 /// * mode: [CollectionMode] collection type and type dependent data.398 // returns collection ID399 #[weight = T::WeightInfo::create_collection()]400 pub fn create_collection(origin,401 collection_name: Vec<u16>,402 collection_description: Vec<u16>,403 token_prefix: Vec<u8>,404 mode: CollectionMode) -> DispatchResult {405406 // Anyone can create a collection407 let who = ensure_signed(origin)?;408409 let decimal_points = match mode {410 CollectionMode::Fungible(points) => points,411 CollectionMode::ReFungible(points) => points,412 _ => 0413 };414415 // bound Total number of collections416 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, "Total collections bound exceeded");417418 // check params419 ensure!(decimal_points <= 4, "decimal_points parameter must be lower than 4");420421 let mut name = collection_name.to_vec();422 name.push(0);423 ensure!(name.len() <= 64, "Collection name can not be longer than 63 char");424425 let mut description = collection_description.to_vec();426 description.push(0);427 ensure!(name.len() <= 256, "Collection description can not be longer than 255 char");428429 let mut prefix = token_prefix.to_vec();430 prefix.push(0);431 ensure!(prefix.len() <= 16, "Token prefix can not be longer than 15 char");432433 // Generate next collection ID434 let next_id = CreatedCollectionCount::get()435 .checked_add(1)436 .expect("collection id error");437438 // bound counter439 let total = CollectionCount::get()440 .checked_add(1)441 .expect("collection counter error");442443 CreatedCollectionCount::put(next_id);444 CollectionCount::put(total);445446 // Create new collection447 let new_collection = CollectionType {448 owner: who.clone(),449 name: name,450 mode: mode.clone(),451 mint_mode: false,452 access: AccessMode::Normal,453 description: description,454 decimal_points: decimal_points,455 token_prefix: prefix,456 offchain_schema: Vec::new(),457 sponsor: T::AccountId::default(),458 unconfirmed_sponsor: T::AccountId::default(),459 variable_on_chain_schema: Vec::new(),460 const_on_chain_schema: Vec::new(),461 };462463 // Add new collection to map464 <Collection<T>>::insert(next_id, new_collection);465466 // call event467 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));468469 Ok(())470 }471472 /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.473 /// 474 /// # Permissions475 /// 476 /// * Collection Owner.477 /// 478 /// # Arguments479 /// 480 /// * collection_id: collection to destroy.481 #[weight = T::WeightInfo::destroy_collection()]482 pub fn destroy_collection(origin, collection_id: u64) -> DispatchResult {483484 let sender = ensure_signed(origin)?;485 Self::check_owner_permissions(collection_id, sender)?;486487 <AddressTokens<T>>::remove_prefix(collection_id);488 <ApprovedList<T>>::remove_prefix(collection_id);489 <Balance<T>>::remove_prefix(collection_id);490 <ItemListIndex>::remove(collection_id);491 <AdminList<T>>::remove(collection_id);492 <Collection<T>>::remove(collection_id);493 <WhiteList<T>>::remove(collection_id);494495 <NftItemList<T>>::remove_prefix(collection_id);496 <FungibleItemList<T>>::remove_prefix(collection_id);497 <ReFungibleItemList<T>>::remove_prefix(collection_id);498499 <NftTransferBasket<T>>::remove_prefix(collection_id);500 <FungibleTransferBasket<T>>::remove_prefix(collection_id);501 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);502503 if CollectionCount::get() > 0504 {505 // bound couter506 let total = CollectionCount::get()507 .checked_sub(1)508 .expect("collection counter error");509510 CollectionCount::put(total);511 }512513 Ok(())514 }515516 /// Add an address to white list.517 /// 518 /// # Permissions519 /// 520 /// * Collection Owner521 /// * Collection Admin522 /// 523 /// # Arguments524 /// 525 /// * collection_id.526 /// 527 /// * address.528 #[weight = T::WeightInfo::add_to_white_list()]529 pub fn add_to_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{530531 let sender = ensure_signed(origin)?;532 Self::check_owner_or_admin_permissions(collection_id, sender)?;533534 let mut white_list_collection: Vec<T::AccountId>;535 if <WhiteList<T>>::contains_key(collection_id) {536 white_list_collection = <WhiteList<T>>::get(collection_id);537 if !white_list_collection.contains(&address.clone())538 {539 white_list_collection.push(address.clone());540 }541 }542 else {543 white_list_collection = Vec::new();544 white_list_collection.push(address.clone());545 }546547 <WhiteList<T>>::insert(collection_id, white_list_collection);548 Ok(())549 }550551 /// Remove an address from white list.552 /// 553 /// # Permissions554 /// 555 /// * Collection Owner556 /// * Collection Admin557 /// 558 /// # Arguments559 /// 560 /// * collection_id.561 /// 562 /// * address.563 #[weight = T::WeightInfo::remove_from_white_list()]564 pub fn remove_from_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{565566 let sender = ensure_signed(origin)?;567 Self::check_owner_or_admin_permissions(collection_id, sender)?;568569 if <WhiteList<T>>::contains_key(collection_id) {570 let mut white_list_collection = <WhiteList<T>>::get(collection_id);571 if white_list_collection.contains(&address.clone())572 {573 white_list_collection.retain(|i| *i != address.clone());574 <WhiteList<T>>::insert(collection_id, white_list_collection);575 }576 }577578 Ok(())579 }580581 /// Toggle between normal and white list access for the methods with access for `Anyone`.582 /// 583 /// # Permissions584 /// 585 /// * Collection Owner.586 /// 587 /// # Arguments588 /// 589 /// * collection_id.590 /// 591 /// * mode: [AccessMode]592 #[weight = T::WeightInfo::set_public_access_mode()]593 pub fn set_public_access_mode(origin, collection_id: u64, mode: AccessMode) -> DispatchResult594 {595 let sender = ensure_signed(origin)?;596597 Self::check_owner_permissions(collection_id, sender)?;598 let mut target_collection = <Collection<T>>::get(collection_id);599 target_collection.access = mode;600 <Collection<T>>::insert(collection_id, target_collection);601602 Ok(())603 }604605 /// Allows Anyone to create tokens if:606 /// * White List is enabled, and607 /// * Address is added to white list, and608 /// * This method was called with True parameter609 /// 610 /// # Permissions611 /// * Collection Owner612 ///613 /// # Arguments614 /// 615 /// * collection_id.616 /// 617 /// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.618 #[weight = T::WeightInfo::set_mint_permission()]619 pub fn set_mint_permission(origin, collection_id: u64, mint_permission: bool) -> DispatchResult620 {621 let sender = ensure_signed(origin)?;622623 Self::check_owner_permissions(collection_id, sender)?;624 let mut target_collection = <Collection<T>>::get(collection_id);625 target_collection.mint_mode = mint_permission;626 <Collection<T>>::insert(collection_id, target_collection);627628 Ok(())629 }630631 /// Change the owner of the collection.632 /// 633 /// # Permissions634 /// 635 /// * Collection Owner.636 /// 637 /// # Arguments638 /// 639 /// * collection_id.640 /// 641 /// * new_owner.642 #[weight = T::WeightInfo::change_collection_owner()]643 pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {644645 let sender = ensure_signed(origin)?;646 Self::check_owner_permissions(collection_id, sender)?;647 let mut target_collection = <Collection<T>>::get(collection_id);648 target_collection.owner = new_owner;649 <Collection<T>>::insert(collection_id, target_collection);650651 Ok(())652 }653654 /// Adds an admin of the Collection.655 /// NFT Collection can be controlled by multiple admin addresses (some which can also be servers, for example). Admins can issue and burn NFTs, as well as add and remove other admins, but cannot change NFT or Collection ownership. 656 /// 657 /// # Permissions658 /// 659 /// * Collection Owner.660 /// * Collection Admin.661 /// 662 /// # Arguments663 /// 664 /// * collection_id: ID of the Collection to add admin for.665 /// 666 /// * new_admin_id: Address of new admin to add.667 #[weight = T::WeightInfo::add_collection_admin()]668 pub fn add_collection_admin(origin, collection_id: u64, new_admin_id: T::AccountId) -> DispatchResult {669670 let sender = ensure_signed(origin)?;671 Self::check_owner_or_admin_permissions(collection_id, sender)?;672 let mut admin_arr: Vec<T::AccountId> = Vec::new();673674 if <AdminList<T>>::contains_key(collection_id)675 {676 admin_arr = <AdminList<T>>::get(collection_id);677 ensure!(!admin_arr.contains(&new_admin_id), "Account already has admin role");678 }679680 // Number of collection admins681 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, "Number of collection admins bound exceeded");682683 admin_arr.push(new_admin_id);684 <AdminList<T>>::insert(collection_id, admin_arr);685686 Ok(())687 }688689 /// Remove admin address of the Collection. An admin address can remove itself. List of admins may become empty, in which case only Collection Owner will be able to add an Admin.690 ///691 /// # Permissions692 /// 693 /// * Collection Owner.694 /// * Collection Admin.695 /// 696 /// # Arguments697 /// 698 /// * collection_id: ID of the Collection to remove admin for.699 /// 700 /// * account_id: Address of admin to remove.701 #[weight = T::WeightInfo::remove_collection_admin()]702 pub fn remove_collection_admin(origin, collection_id: u64, account_id: T::AccountId) -> DispatchResult {703704 let sender = ensure_signed(origin)?;705 Self::check_owner_or_admin_permissions(collection_id, sender)?;706707 if <AdminList<T>>::contains_key(collection_id)708 {709 let mut admin_arr = <AdminList<T>>::get(collection_id);710 admin_arr.retain(|i| *i != account_id);711 <AdminList<T>>::insert(collection_id, admin_arr);712 }713714 Ok(())715 }716717 /// # Permissions718 /// 719 /// * Collection Owner720 /// 721 /// # Arguments722 /// 723 /// * collection_id.724 /// 725 /// * new_sponsor.726 #[weight = T::WeightInfo::set_collection_sponsor()]727 pub fn set_collection_sponsor(origin, collection_id: u64, new_sponsor: T::AccountId) -> DispatchResult {728729 let sender = ensure_signed(origin)?;730 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");731732 let mut target_collection = <Collection<T>>::get(collection_id);733 ensure!(sender == target_collection.owner, "You do not own this collection");734735 target_collection.unconfirmed_sponsor = new_sponsor;736 <Collection<T>>::insert(collection_id, target_collection);737738 Ok(())739 }740741 /// # Permissions742 /// 743 /// * Sponsor.744 /// 745 /// # Arguments746 /// 747 /// * collection_id.748 #[weight = T::WeightInfo::confirm_sponsorship()]749 pub fn confirm_sponsorship(origin, collection_id: u64) -> DispatchResult {750751 let sender = ensure_signed(origin)?;752 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");753754 let mut target_collection = <Collection<T>>::get(collection_id);755 ensure!(sender == target_collection.unconfirmed_sponsor, "This address is not set as sponsor, use setCollectionSponsor first");756757 target_collection.sponsor = target_collection.unconfirmed_sponsor;758 target_collection.unconfirmed_sponsor = T::AccountId::default();759 <Collection<T>>::insert(collection_id, target_collection);760761 Ok(())762 }763764 /// Switch back to pay-per-own-transaction model.765 ///766 /// # Permissions767 ///768 /// * Collection owner.769 /// 770 /// # Arguments771 /// 772 /// * collection_id.773 #[weight = T::WeightInfo::remove_collection_sponsor()]774 pub fn remove_collection_sponsor(origin, collection_id: u64) -> DispatchResult {775776 let sender = ensure_signed(origin)?;777 ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");778779 let mut target_collection = <Collection<T>>::get(collection_id);780 ensure!(sender == target_collection.owner, "You do not own this collection");781782 target_collection.sponsor = T::AccountId::default();783 <Collection<T>>::insert(collection_id, target_collection);784785 Ok(())786 }787788 /// This method creates a concrete instance of NFT Collection created with CreateCollection method.789 /// 790 /// # Permissions791 /// 792 /// * Collection Owner.793 /// * Collection Admin.794 /// * Anyone if795 /// * White List is enabled, and796 /// * Address is added to white list, and797 /// * MintPermission is enabled (see SetMintPermission method)798 /// 799 /// # Arguments800 /// 801 /// * collection_id: ID of the collection.802 /// 803 /// * owner: Address, initial owner of the NFT.804 ///805 /// * data: Token data to store on chain.806 // #[weight =807 // (130_000_000 as Weight)808 // .saturating_add((2135 as Weight).saturating_mul((properties.len() as u64) as Weight))809 // .saturating_add(RocksDbWeight::get().reads(10 as Weight))810 // .saturating_add(RocksDbWeight::get().writes(8 as Weight))]811812 #[weight = T::WeightInfo::create_item(data.len())]813 pub fn create_item(origin, collection_id: u64, owner: T::AccountId, data: CreateItemData) -> DispatchResult {814815 let sender = ensure_signed(origin)?;816 Self::collection_exists(collection_id)?;817 let target_collection = <Collection<T>>::get(collection_id);818819 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {820 ensure!(target_collection.mint_mode == true, "Public minting is not allowed for this collection.");821 Self::check_white_list(collection_id, &owner)?;822 Self::check_white_list(collection_id, &sender)?;823 }824825 match target_collection.mode826 {827 CollectionMode::NFT => {828 if let CreateItemData::NFT(data) = data {829 // check sizes830 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, "const_data exceeded data limit.");831 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, "variable_data exceeded data limit.");832 833 // Create nft item834 let item = NftItemType {835 collection: collection_id,836 owner: owner,837 const_data: data.const_data.clone(),838 variable_data: data.variable_data.clone() 839 };840 841 Self::add_nft_item(item)?;842 843 } else {844 fail!("Not NFT item data used to mint in NFT collection.");845 }846 },847 CollectionMode::Fungible(_) => {848 if let CreateItemData::Fungible(_) = data {849 850 let item = FungibleItemType {851 collection: collection_id,852 owner: owner,853 value: (10 as u128).pow(target_collection.decimal_points)854 };855 856 Self::add_fungible_item(item)?;857 } else {858 fail!("Not Fungible item data used to mint in Fungible collection.");859 }860 },861 CollectionMode::ReFungible(_) => {862 if let CreateItemData::ReFungible(data) = data {863 864 // check sizes865 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, "const_data exceeded data limit.");866 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, "variable_data exceeded data limit.");867 868 let mut owner_list = Vec::new();869 let value = (10 as u128).pow(target_collection.decimal_points);870 owner_list.push(Ownership {owner: owner.clone(), fraction: value});871 872 let item = ReFungibleItemType {873 collection: collection_id,874 owner: owner_list,875 const_data: data.const_data.clone(),876 variable_data: data.variable_data.clone() 877 };878 879 Self::add_refungible_item(item)?;880 } else {881 fail!("Not Re Fungible item data used to mint in Re Fungible collection.");882 }883 },884 _ => { ensure!(1 == 0,"Unexpected collection type."); }885 };886887 // call event888 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));889890 Ok(())891 }892893 /// Destroys a concrete instance of NFT.894 /// 895 /// # Permissions896 /// 897 /// * Collection Owner.898 /// * Collection Admin.899 /// * Current NFT Owner.900 /// 901 /// # Arguments902 /// 903 /// * collection_id: ID of the collection.904 /// 905 /// * item_id: ID of NFT to burn.906 #[weight = T::WeightInfo::burn_item()]907 pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {908909 let sender = ensure_signed(origin)?;910 Self::collection_exists(collection_id)?;911912 // Transfer permissions check913 let target_collection = <Collection<T>>::get(collection_id);914 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||915 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),916 "Only item owner, collection owner and admins can modify item");917918 if target_collection.access == AccessMode::WhiteList {919 Self::check_white_list(collection_id, &sender)?;920 }921922 match target_collection.mode923 {924 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,925 CollectionMode::Fungible(_) => Self::burn_fungible_item(collection_id, item_id)?,926 CollectionMode::ReFungible(_) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,927 _ => ()928 };929930 // call event931 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));932933 Ok(())934 }935936 /// Change ownership of the token.937 /// 938 /// # Permissions939 /// 940 /// * Collection Owner941 /// * Collection Admin942 /// * Current NFT owner943 ///944 /// # Arguments945 /// 946 /// * recipient: Address of token recipient.947 /// 948 /// * collection_id.949 /// 950 /// * item_id: ID of the item951 /// * Non-Fungible Mode: Required.952 /// * Fungible Mode: Ignored.953 /// * Re-Fungible Mode: Required.954 /// 955 /// * value: Amount to transfer.956 /// * Non-Fungible Mode: Ignored957 /// * Fungible Mode: Must specify transferred amount958 /// * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)959 #[weight = T::WeightInfo::transfer()]960 pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {961962 let sender = ensure_signed(origin)?;963964 // Transfer permissions check965 let target_collection = <Collection<T>>::get(collection_id);966 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||967 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),968 "Only item owner, collection owner and admins can modify item");969970 if target_collection.access == AccessMode::WhiteList {971 Self::check_white_list(collection_id, &sender)?;972 Self::check_white_list(collection_id, &recipient)?;973 }974975 match target_collection.mode976 {977 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,978 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,979 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,980 _ => ()981 };982983 Ok(())984 }985986 /// Set, change, or remove approved address to transfer the ownership of the NFT.987 /// 988 /// # Permissions989 /// 990 /// * Collection Owner991 /// * Collection Admin992 /// * Current NFT owner993 /// 994 /// # Arguments995 /// 996 /// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).997 /// 998 /// * collection_id.999 /// 1000 /// * item_id: ID of the item.1001 #[weight = T::WeightInfo::approve()]1002 pub fn approve(origin, approved: T::AccountId, collection_id: u64, item_id: u64) -> DispatchResult {10031004 let sender = ensure_signed(origin)?;10051006 // Transfer permissions check1007 let target_collection = <Collection<T>>::get(collection_id);1008 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1009 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1010 "Only item owner, collection owner and admins can approve");10111012 if target_collection.access == AccessMode::WhiteList {1013 Self::check_white_list(collection_id, &sender)?;1014 Self::check_white_list(collection_id, &approved)?;1015 }10161017 // amount param stub1018 let amount = 100000000;10191020 let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));1021 if list_exists {10221023 let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));1024 let item_contains = list.iter().any(|i| i.approved == approved);10251026 if !item_contains {1027 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1028 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1029 }1030 } else {10311032 let mut list = Vec::new();1033 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1034 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1035 }10361037 Ok(())1038 }1039 1040 /// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.1041 /// 1042 /// # Permissions1043 /// * Collection Owner1044 /// * Collection Admin1045 /// * Current NFT owner1046 /// * Address approved by current NFT owner1047 /// 1048 /// # Arguments1049 /// 1050 /// * from: Address that owns token.1051 /// 1052 /// * recipient: Address of token recipient.1053 /// 1054 /// * collection_id.1055 /// 1056 /// * item_id: ID of the item.1057 /// 1058 /// * value: Amount to transfer.1059 #[weight = T::WeightInfo::transfer_from()]1060 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64 ) -> DispatchResult {10611062 let sender = ensure_signed(origin)?;1063 let mut appoved_transfer = false;10641065 // Check approve1066 if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {1067 let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));1068 let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());1069 if opt_item.is_some()1070 {1071 appoved_transfer = true;1072 ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");1073 }1074 }10751076 // Transfer permissions check1077 let target_collection = <Collection<T>>::get(collection_id);1078 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1079 "Only item owner, collection owner and admins can modify items");10801081 if target_collection.access == AccessMode::WhiteList {1082 Self::check_white_list(collection_id, &sender)?;1083 Self::check_white_list(collection_id, &recipient)?;1084 }10851086 // remove approve1087 let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))1088 .into_iter().filter(|i| i.approved != sender.clone()).collect();1089 <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);109010911092 match target_collection.mode1093 {1094 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1095 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1096 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1097 _ => ()1098 };10991100 Ok(())1101 }11021103 ///1104 #[weight = 0]1105 pub fn safe_transfer_from(origin, collection_id: u64, item_id: u64, new_owner: T::AccountId) -> DispatchResult {11061107 // let no_perm_mes = "You do not have permissions to modify this collection";1108 // ensure!(<ApprovedList<T>>::contains_key((collection_id, item_id)), no_perm_mes);1109 // let list_itm = <ApprovedList<T>>::get((collection_id, item_id));1110 // ensure!(list_itm.contains(&new_owner.clone()), no_perm_mes);11111112 // // on_nft_received call11131114 // Self::transfer(origin, collection_id, item_id, new_owner)?;11151116 Ok(())1117 }1118 1119 /// Set off-chain data schema.1120 /// 1121 /// # Permissions1122 /// 1123 /// * Collection Owner1124 /// * Collection Admin1125 /// 1126 /// # Arguments1127 /// 1128 /// * collection_id.1129 /// 1130 /// * schema: String representing the offchain data schema.1131 #[weight = T::WeightInfo::set_variable_meta_data()]1132 pub fn set_variable_meta_data (1133 origin,1134 collection_id: u64,1135 item_id: u64,1136 data: Vec<u8>1137 ) -> DispatchResult {1138 let sender = ensure_signed(origin)?;1139 1140 Self::collection_exists(collection_id)?;11411142 // Modify permissions check1143 let target_collection = <Collection<T>>::get(collection_id);1144 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1145 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1146 "Only item owner, collection owner and admins can modify item");11471148 Self::item_exists(collection_id, item_id, &target_collection.mode)?;11491150 match target_collection.mode1151 {1152 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1153 CollectionMode::ReFungible(_) => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1154 _ => ()1155 };11561157 Ok(())1158 }1159 11601161 /// Set off-chain data schema.1162 /// 1163 /// # Permissions1164 /// 1165 /// * Collection Owner1166 /// * Collection Admin1167 /// 1168 /// # Arguments1169 /// 1170 /// * collection_id.1171 /// 1172 /// * schema: String representing the offchain data schema.1173 #[weight = T::WeightInfo::set_offchain_schema()]1174 pub fn set_offchain_schema(1175 origin,1176 collection_id: u64,1177 schema: Vec<u8>1178 ) -> DispatchResult {1179 let sender = ensure_signed(origin)?;1180 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;11811182 let mut target_collection = <Collection<T>>::get(collection_id);1183 target_collection.offchain_schema = schema;1184 <Collection<T>>::insert(collection_id, target_collection);11851186 Ok(())1187 }11881189 /// Set const on-chain data schema.1190 /// 1191 /// # Permissions1192 /// 1193 /// * Collection Owner1194 /// * Collection Admin1195 /// 1196 /// # Arguments1197 /// 1198 /// * collection_id.1199 /// 1200 /// * schema: String representing the const on-chain data schema.1201 #[weight = T::WeightInfo::set_const_on_chain_schema()]1202 pub fn set_const_on_chain_schema (1203 origin,1204 collection_id: u64,1205 schema: Vec<u8>1206 ) -> DispatchResult {1207 let sender = ensure_signed(origin)?;1208 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12091210 let mut target_collection = <Collection<T>>::get(collection_id);1211 target_collection.const_on_chain_schema = schema;1212 <Collection<T>>::insert(collection_id, target_collection);12131214 Ok(())1215 }12161217 /// Set variable on-chain data schema.1218 /// 1219 /// # Permissions1220 /// 1221 /// * Collection Owner1222 /// * Collection Admin1223 /// 1224 /// # Arguments1225 /// 1226 /// * collection_id.1227 /// 1228 /// * schema: String representing the variable on-chain data schema.1229 #[weight = T::WeightInfo::set_const_on_chain_schema()]1230 pub fn set_variable_on_chain_schema (1231 origin,1232 collection_id: u64,1233 schema: Vec<u8>1234 ) -> DispatchResult {1235 let sender = ensure_signed(origin)?;1236 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12371238 let mut target_collection = <Collection<T>>::get(collection_id);1239 target_collection.variable_on_chain_schema = schema;1240 <Collection<T>>::insert(collection_id, target_collection);12411242 Ok(())1243 }12441245 // Sudo permissions function1246 #[weight = 0]1247 pub fn set_chain_limits(1248 origin,1249 limits: ChainLimits1250 ) -> DispatchResult {1251 ensure_root(origin)?;1252 <ChainLimit>::put(limits);1253 Ok(())1254 } 1255 }1256}12571258impl<T: Trait> Module<T> {1259 fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1260 let current_index = <ItemListIndex>::get(item.collection)1261 .checked_add(1)1262 .expect("Item list index id error");1263 let itemcopy = item.clone();1264 let owner = item.owner.clone();1265 let value = item.value as u64;12661267 Self::add_token_index(item.collection, current_index, owner.clone())?;12681269 <ItemListIndex>::insert(item.collection, current_index);1270 <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);12711272 // Add current block1273 let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1274 <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);1275 1276 // Update balance1277 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1278 .checked_add(value)1279 .unwrap();1280 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);12811282 Ok(())1283 }12841285 fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1286 let current_index = <ItemListIndex>::get(item.collection)1287 .checked_add(1)1288 .expect("Item list index id error");1289 let itemcopy = item.clone();12901291 let value = item.owner.first().unwrap().fraction as u64;1292 let owner = item.owner.first().unwrap().owner.clone();12931294 Self::add_token_index(item.collection, current_index, owner.clone())?;12951296 <ItemListIndex>::insert(item.collection, current_index);1297 <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);12981299 // Add current block1300 let block_number: T::BlockNumber = 0.into();1301 <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);13021303 // Update balance1304 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1305 .checked_add(value)1306 .unwrap();1307 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);13081309 Ok(())1310 }13111312 fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {1313 let current_index = <ItemListIndex>::get(item.collection)1314 .checked_add(1)1315 .expect("Item list index id error");13161317 let item_owner = item.owner.clone();1318 let collection_id = item.collection.clone();1319 Self::add_token_index(collection_id, current_index, item.owner.clone())?;13201321 <ItemListIndex>::insert(collection_id, current_index);1322 <NftItemList<T>>::insert(collection_id, current_index, item);13231324 // Add current block1325 let block_number: T::BlockNumber = 0.into();1326 <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);13271328 // Update balance1329 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1330 .checked_add(1)1331 .unwrap();1332 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);13331334 Ok(())1335 }13361337 fn burn_refungible_item(1338 collection_id: u64,1339 item_id: u64,1340 owner: T::AccountId,1341 ) -> DispatchResult {1342 ensure!(1343 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1344 "Item does not exists"1345 );1346 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1347 let item = collection1348 .owner1349 .iter()1350 .filter(|&i| i.owner == owner)1351 .next()1352 .unwrap();1353 Self::remove_token_index(collection_id, item_id, owner.clone())?;13541355 // remove approve list1356 <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));13571358 // update balance1359 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1360 .checked_sub(item.fraction as u64)1361 .unwrap();1362 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);13631364 <ReFungibleItemList<T>>::remove(collection_id, item_id);13651366 Ok(())1367 }13681369 fn burn_nft_item(collection_id: u64, item_id: u64) -> DispatchResult {1370 ensure!(1371 <NftItemList<T>>::contains_key(collection_id, item_id),1372 "Item does not exists"1373 );1374 let item = <NftItemList<T>>::get(collection_id, item_id);1375 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;13761377 // remove approve list1378 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));13791380 // update balance1381 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1382 .checked_sub(1)1383 .unwrap();1384 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1385 <NftItemList<T>>::remove(collection_id, item_id);13861387 Ok(())1388 }13891390 fn burn_fungible_item(collection_id: u64, item_id: u64) -> DispatchResult {1391 ensure!(1392 <FungibleItemList<T>>::contains_key(collection_id, item_id),1393 "Item does not exists"1394 );1395 let item = <FungibleItemList<T>>::get(collection_id, item_id);1396 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;13971398 // remove approve list1399 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));14001401 // update balance1402 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1403 .checked_sub(item.value as u64)1404 .unwrap();1405 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);14061407 <FungibleItemList<T>>::remove(collection_id, item_id);14081409 Ok(())1410 }14111412 fn collection_exists(collection_id: u64) -> DispatchResult {1413 ensure!(1414 <Collection<T>>::contains_key(collection_id),1415 "This collection does not exist"1416 );1417 Ok(())1418 }14191420 fn check_owner_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult {1421 Self::collection_exists(collection_id)?;14221423 let target_collection = <Collection<T>>::get(collection_id);1424 ensure!(1425 subject == target_collection.owner,1426 "You do not own this collection"1427 );14281429 Ok(())1430 }14311432 fn is_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> bool {1433 let target_collection = <Collection<T>>::get(collection_id);1434 let mut result: bool = subject == target_collection.owner;1435 let exists = <AdminList<T>>::contains_key(collection_id);14361437 if !result & exists {1438 if <AdminList<T>>::get(collection_id).contains(&subject) {1439 result = true1440 }1441 }14421443 result1444 }14451446 fn check_owner_or_admin_permissions(1447 collection_id: u64,1448 subject: T::AccountId,1449 ) -> DispatchResult {1450 Self::collection_exists(collection_id)?;1451 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());14521453 ensure!(1454 result,1455 "You do not have permissions to modify this collection"1456 );1457 Ok(())1458 }14591460 fn is_item_owner(subject: T::AccountId, collection_id: u64, item_id: u64) -> bool {1461 let target_collection = <Collection<T>>::get(collection_id);14621463 match target_collection.mode {1464 CollectionMode::NFT => {1465 <NftItemList<T>>::get(collection_id, item_id).owner == subject1466 }1467 CollectionMode::Fungible(_) => {1468 <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1469 }1470 CollectionMode::ReFungible(_) => {1471 <ReFungibleItemList<T>>::get(collection_id, item_id)1472 .owner1473 .iter()1474 .any(|i| i.owner == subject)1475 }1476 CollectionMode::Invalid => false,1477 }1478 }14791480 fn check_white_list(collection_id: u64, address: &T::AccountId) -> DispatchResult {1481 let mes = "Address is not in white list";1482 ensure!(<WhiteList<T>>::contains_key(collection_id), mes);1483 let wl = <WhiteList<T>>::get(collection_id);1484 ensure!(wl.contains(address), mes);14851486 Ok(())1487 }14881489 fn transfer_fungible(1490 collection_id: u64,1491 item_id: u64,1492 value: u64,1493 owner: T::AccountId,1494 new_owner: T::AccountId,1495 ) -> DispatchResult {1496 ensure!(1497 <FungibleItemList<T>>::contains_key(collection_id, item_id),1498 "Item not exists"1499 );15001501 let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1502 let amount = full_item.value;15031504 ensure!(amount >= value.into(), "Item balance not enouth");15051506 // update balance1507 let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1508 .checked_sub(value)1509 .unwrap();1510 <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);15111512 let mut new_owner_account_id = 0;1513 let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1514 if new_owner_items.len() > 0 {1515 new_owner_account_id = new_owner_items[0];1516 }15171518 let val64 = value.into();15191520 // transfer1521 if amount == val64 && new_owner_account_id == 0 {1522 // change owner1523 // new owner do not have account1524 let mut new_full_item = full_item.clone();1525 new_full_item.owner = new_owner.clone();1526 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);15271528 // update balance1529 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1530 .checked_add(value)1531 .unwrap();1532 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);15331534 // update index collection1535 Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1536 } else {1537 let mut new_full_item = full_item.clone();1538 new_full_item.value -= val64;15391540 // separate amount1541 if new_owner_account_id > 0 {1542 // new owner has account1543 let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1544 item.value += val64;15451546 // update balance1547 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1548 .checked_add(value)1549 .unwrap();1550 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);15511552 <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1553 } else {1554 // new owner do not have account1555 let item = FungibleItemType {1556 collection: collection_id,1557 owner: new_owner.clone(),1558 value: val64,1559 };15601561 Self::add_fungible_item(item)?;1562 }15631564 if amount == val64 {1565 Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;15661567 // remove approve list1568 <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1569 <FungibleItemList<T>>::remove(collection_id, item_id);1570 }15711572 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1573 }15741575 Ok(())1576 }15771578 fn transfer_refungible(1579 collection_id: u64,1580 item_id: u64,1581 value: u64,1582 owner: T::AccountId,1583 new_owner: T::AccountId,1584 ) -> DispatchResult {1585 ensure!(1586 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1587 "Item not exists"1588 );15891590 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1591 let item = full_item1592 .owner1593 .iter()1594 .filter(|i| i.owner == owner)1595 .next()1596 .unwrap();1597 let amount = item.fraction;15981599 ensure!(amount >= value.into(), "Item balance not enouth");16001601 // update balance1602 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1603 .checked_sub(value)1604 .unwrap();1605 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);16061607 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1608 .checked_add(value)1609 .unwrap();1610 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);16111612 let old_owner = item.owner.clone();1613 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);1614 let val64 = value.into();16151616 // transfer1617 if amount == val64 && !new_owner_has_account {1618 // change owner1619 // new owner do not have account1620 let mut new_full_item = full_item.clone();1621 new_full_item1622 .owner1623 .iter_mut()1624 .find(|i| i.owner == owner)1625 .unwrap()1626 .owner = new_owner.clone();1627 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);16281629 // update index collection1630 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1631 } else {1632 let mut new_full_item = full_item.clone();1633 new_full_item1634 .owner1635 .iter_mut()1636 .find(|i| i.owner == owner)1637 .unwrap()1638 .fraction -= val64;16391640 // separate amount1641 if new_owner_has_account {1642 // new owner has account1643 new_full_item1644 .owner1645 .iter_mut()1646 .find(|i| i.owner == new_owner)1647 .unwrap()1648 .fraction += val64;1649 } else {1650 // new owner do not have account1651 new_full_item.owner.push(Ownership {1652 owner: new_owner.clone(),1653 fraction: val64,1654 });1655 Self::add_token_index(collection_id, item_id, new_owner.clone())?;1656 }16571658 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1659 }16601661 Ok(())1662 }16631664 fn transfer_nft(1665 collection_id: u64,1666 item_id: u64,1667 sender: T::AccountId,1668 new_owner: T::AccountId,1669 ) -> DispatchResult {1670 ensure!(1671 <NftItemList<T>>::contains_key(collection_id, item_id),1672 "Item not exists"1673 );16741675 let mut item = <NftItemList<T>>::get(collection_id, item_id);16761677 ensure!(1678 sender == item.owner,1679 "sender parameter and item owner must be equal"1680 );16811682 // update balance1683 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1684 .checked_sub(1)1685 .unwrap();1686 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);16871688 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1689 .checked_add(1)1690 .unwrap();1691 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);16921693 // change owner1694 let old_owner = item.owner.clone();1695 item.owner = new_owner.clone();1696 <NftItemList<T>>::insert(collection_id, item_id, item);16971698 // update index collection1699 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;17001701 // reset approved list1702 <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));1703 Ok(())1704 }1705 1706 fn item_exists(1707 collection_id: u64,1708 item_id: u64,1709 mode: &CollectionMode1710 ) -> DispatchResult {1711 match mode {1712 CollectionMode::NFT => ensure!(<NftItemList<T>>::contains_key(collection_id, item_id), "Item does not exists"),1713 CollectionMode::ReFungible(_) => ensure!(<ReFungibleItemList<T>>::contains_key(collection_id, item_id), "Item does not exists"),1714 CollectionMode::Fungible(_) => ensure!(<FungibleItemList<T>>::contains_key(collection_id, item_id), "Item does not exists"),1715 _ => ()1716 };1717 1718 Ok(())1719 }17201721 fn set_re_fungible_variable_data(1722 collection_id: u64,1723 item_id: u64,1724 data: Vec<u8>1725 ) -> DispatchResult {1726 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);17271728 item.variable_data = data;17291730 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);17311732 Ok(())1733 }17341735 fn set_nft_variable_data(1736 collection_id: u64,1737 item_id: u64,1738 data: Vec<u8>1739 ) -> DispatchResult {1740 let mut item = <NftItemList<T>>::get(collection_id, item_id);1741 1742 item.variable_data = data;17431744 <NftItemList<T>>::insert(collection_id, item_id, item);1745 1746 Ok(())1747 }17481749 fn init_collection(item: &CollectionType<T::AccountId>) {1750 // check params1751 assert!(1752 item.decimal_points <= 4,1753 "decimal_points parameter must be lower than 4"1754 );1755 assert!(1756 item.name.len() <= 64,1757 "Collection name can not be longer than 63 char"1758 );1759 assert!(1760 item.name.len() <= 256,1761 "Collection description can not be longer than 255 char"1762 );1763 assert!(1764 item.token_prefix.len() <= 16,1765 "Token prefix can not be longer than 15 char"1766 );17671768 // Generate next collection ID1769 let next_id = CreatedCollectionCount::get()1770 .checked_add(1)1771 .expect("collection id error");17721773 CreatedCollectionCount::put(next_id);1774 }17751776 fn init_nft_token(item: &NftItemType<T::AccountId>) {1777 let current_index = <ItemListIndex>::get(item.collection)1778 .checked_add(1)1779 .expect("Item list index id error");17801781 let item_owner = item.owner.clone();1782 let collection_id = item.collection.clone();1783 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();17841785 <ItemListIndex>::insert(collection_id, current_index);17861787 // Update balance1788 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1789 .checked_add(1)1790 .unwrap();1791 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);1792 }17931794 fn init_fungible_token(item: &FungibleItemType<T::AccountId>) {1795 let current_index = <ItemListIndex>::get(item.collection)1796 .checked_add(1)1797 .expect("Item list index id error");1798 let owner = item.owner.clone();1799 let value = item.value as u64;18001801 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();18021803 <ItemListIndex>::insert(item.collection, current_index);18041805 // Update balance1806 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1807 .checked_add(value)1808 .unwrap();1809 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1810 }18111812 fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {1813 let current_index = <ItemListIndex>::get(item.collection)1814 .checked_add(1)1815 .expect("Item list index id error");18161817 let value = item.owner.first().unwrap().fraction as u64;1818 let owner = item.owner.first().unwrap().owner.clone();18191820 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();18211822 <ItemListIndex>::insert(item.collection, current_index);18231824 // Update balance1825 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1826 .checked_add(value)1827 .unwrap();1828 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1829 }18301831 fn add_token_index(collection_id: u64, item_index: u64, owner: T::AccountId) -> DispatchResult {18321833 // add to account limit1834 if <AccountItemCount<T>>::contains_key(owner.clone()) {18351836 // bound Owned tokens by a single address1837 let count = <AccountItemCount<T>>::get(owner.clone());1838 ensure!(count < ChainLimit::get().account_token_ownership_limit, "Owned tokens by a single address bound exceeded");18391840 <AccountItemCount<T>>::insert(owner.clone(), 1841 count.checked_add(1).unwrap());1842 }1843 else {1844 <AccountItemCount<T>>::insert(owner.clone(), 1);1845 }18461847 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1848 if list_exists {1849 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1850 let item_contains = list.contains(&item_index.clone());18511852 if !item_contains {1853 list.push(item_index.clone());1854 }18551856 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);1857 } else {1858 let mut itm = Vec::new();1859 itm.push(item_index.clone());1860 <AddressTokens<T>>::insert(collection_id, owner, itm);1861 1862 }18631864 Ok(())1865 }18661867 fn remove_token_index(1868 collection_id: u64,1869 item_index: u64,1870 owner: T::AccountId,1871 ) -> DispatchResult {18721873 // update counter1874 <AccountItemCount<T>>::insert(owner.clone(), 1875 <AccountItemCount<T>>::get(owner.clone()).checked_sub(1).unwrap());187618771878 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1879 if list_exists {1880 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1881 let item_contains = list.contains(&item_index.clone());18821883 if item_contains {1884 list.retain(|&item| item != item_index);1885 <AddressTokens<T>>::insert(collection_id, owner, list);1886 }1887 }18881889 Ok(())1890 }18911892 fn move_token_index(1893 collection_id: u64,1894 item_index: u64,1895 old_owner: T::AccountId,1896 new_owner: T::AccountId,1897 ) -> DispatchResult {1898 Self::remove_token_index(collection_id, item_index, old_owner)?;1899 Self::add_token_index(collection_id, item_index, new_owner)?;19001901 Ok(())1902 }1903}19041905////////////////////////////////////////////////////////////////////////////////////////////////////1906// Economic models1907// #region19081909/// Fee multiplier.1910pub type Multiplier = FixedU128;19111912type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1913 <T as system::Trait>::AccountId,1914>>::Balance;1915type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1916 <T as system::Trait>::AccountId,1917>>::NegativeImbalance;19181919/// Require the transactor pay for themselves and maybe include a tip to gain additional priority1920/// in the queue.1921#[derive(Encode, Decode, Clone, Eq, PartialEq)]1922pub struct ChargeTransactionPayment<T: transaction_payment::Trait + Send + Sync>(1923 #[codec(compact)] BalanceOf<T>,1924);19251926impl<T: Trait + transaction_payment::Trait + Send + Sync> sp_std::fmt::Debug1927 for ChargeTransactionPayment<T>1928{1929 #[cfg(feature = "std")]1930 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1931 write!(f, "ChargeTransactionPayment<{:?}>", self.0)1932 }1933 #[cfg(not(feature = "std"))]1934 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1935 Ok(())1936 }1937}19381939impl<T: Trait + transaction_payment::Trait + Send + Sync> ChargeTransactionPayment<T>1940where1941 T::Call:1942 Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>>,1943 BalanceOf<T>: Send + Sync + FixedPointOperand,1944{1945 /// utility constructor. Used only in client/factory code.1946 pub fn from(fee: BalanceOf<T>) -> Self {1947 Self(fee)1948 }19491950 pub fn traditional_fee(1951 len: usize,1952 info: &DispatchInfoOf<T::Call>,1953 tip: BalanceOf<T>,1954 ) -> BalanceOf<T>1955 where1956 T::Call: Dispatchable<Info = DispatchInfo>,1957 {1958 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)1959 }19601961 fn withdraw_fee(1962 &self,1963 who: &T::AccountId,1964 call: &T::Call,1965 info: &DispatchInfoOf<T::Call>,1966 len: usize,1967 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {1968 let tip = self.0;19691970 // Set fee based on call type. Creating collection costs 1 Unique.1971 // All other transactions have traditional fees so far1972 let fee = match call.is_sub_type() {1973 Some(Call::create_collection(..)) => <BalanceOf<T>>::from(1_000_000_000),1974 _ => Self::traditional_fee(len, info, tip), // Flat fee model, use only for testing purposes1975 // _ => <BalanceOf<T>>::from(100)1976 };19771978 // Determine who is paying transaction fee based on ecnomic model1979 // Parse call to extract collection ID and access collection sponsor1980 let sponsor: T::AccountId = match call.is_sub_type() {1981 Some(Call::create_item(collection_id, _properties, _owner)) => {1982 <Collection<T>>::get(collection_id).sponsor1983 }1984 Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {1985 let _collection_mode = <Collection<T>>::get(collection_id).mode;19861987 // sponsor timeout1988 let sponsor_transfer = match _collection_mode {1989 CollectionMode::NFT => {1990 let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);1991 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1992 let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();1993 if block_number >= limit_time {1994 <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);1995 true1996 }1997 else {1998 false1999 }2000 }2001 CollectionMode::Fungible(_) => {2002 let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);2003 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2004 if basket.iter().any(|i| i.address == _new_owner.clone())2005 {2006 let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();2007 let limit_time = item.start_block + ChainLimit::get().fungible_sponsor_transfer_timeout.into();2008 if block_number >= limit_time {2009 basket.retain(|x| x.address == item.address);2010 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });2011 <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);2012 true2013 }2014 else {2015 false2016 }2017 }2018 else {2019 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});2020 true2021 }2022 }2023 CollectionMode::ReFungible(_) => {2024 let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);2025 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2026 let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();2027 if block_number >= limit_time {2028 <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);2029 true2030 } else {2031 false2032 }2033 }2034 _ => {2035 false2036 },2037 };20382039 if !sponsor_transfer {2040 T::AccountId::default()2041 } else {2042 <Collection<T>>::get(collection_id).sponsor2043 }2044 }20452046 _ => T::AccountId::default(),2047 };20482049 let mut who_pays_fee: T::AccountId = sponsor.clone();2050 if sponsor == T::AccountId::default() {2051 who_pays_fee = who.clone();2052 }20532054 // Only mess with balances if fee is not zero.2055 if fee.is_zero() {2056 return Ok((fee, None));2057 }20582059 match <T as transaction_payment::Trait>::Currency::withdraw(2060 &who_pays_fee,2061 fee,2062 if tip.is_zero() {2063 WithdrawReason::TransactionPayment.into()2064 } else {2065 WithdrawReason::TransactionPayment | WithdrawReason::Tip2066 },2067 ExistenceRequirement::KeepAlive,2068 ) {2069 Ok(imbalance) => Ok((fee, Some(imbalance))),2070 Err(_) => Err(InvalidTransaction::Payment.into()),2071 }2072 }2073}20742075impl<T: Trait + transaction_payment::Trait + Send + Sync> SignedExtension2076 for ChargeTransactionPayment<T>2077where2078 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2079 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>>,2080{2081 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2082 type AccountId = T::AccountId;2083 type Call = T::Call;2084 type AdditionalSigned = ();2085 type Pre = (2086 BalanceOf<T>,2087 Self::AccountId,2088 Option<NegativeImbalanceOf<T>>,2089 BalanceOf<T>,2090 );2091 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2092 Ok(())2093 }20942095 fn validate(2096 &self,2097 who: &Self::AccountId,2098 call: &Self::Call,2099 info: &DispatchInfoOf<Self::Call>,2100 len: usize,2101 ) -> TransactionValidity {2102 let (fee, _) = self.withdraw_fee(who, call, info, len)?;21032104 let mut r = ValidTransaction::default();2105 // NOTE: we probably want to maximize the _fee (of any type) per weight unit_ here, which2106 // will be a bit more than setting the priority to tip. For now, this is enough.2107 r.priority = fee.saturated_into::<TransactionPriority>();2108 Ok(r)2109 }21102111 fn pre_dispatch(2112 self,2113 who: &Self::AccountId,2114 call: &Self::Call,2115 info: &DispatchInfoOf<Self::Call>,2116 len: usize,2117 ) -> Result<Self::Pre, TransactionValidityError> {2118 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2119 Ok((self.0, who.clone(), imbalance, fee))2120 }21212122 fn post_dispatch(2123 pre: Self::Pre,2124 info: &DispatchInfoOf<Self::Call>,2125 post_info: &PostDispatchInfoOf<Self::Call>,2126 len: usize,2127 _result: &DispatchResult,2128 ) -> Result<(), TransactionValidityError> {2129 let (tip, who, imbalance, fee) = pre;2130 if let Some(payed) = imbalance {2131 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2132 len as u32, info, post_info, tip,2133 );2134 let refund = fee.saturating_sub(actual_fee);2135 let actual_payment =2136 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2137 &who, refund,2138 ) {2139 Ok(refund_imbalance) => {2140 // The refund cannot be larger than the up front payed max weight.2141 // `PostDispatchInfo::calc_unspent` guards against such a case.2142 match payed.offset(refund_imbalance) {2143 Ok(actual_payment) => actual_payment,2144 Err(_) => return Err(InvalidTransaction::Payment.into()),2145 }2146 }2147 // We do not recreate the account using the refund. The up front payment2148 // is gone in that case.2149 Err(_) => payed,2150 };2151 let imbalances = actual_payment.split(tip);2152 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2153 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2154 );2155 }2156 Ok(())2157 }2158}2159// #endregion21602161pallets/nft/src/tests.rsdiffbeforeafterboth--- a/pallets/nft/src/tests.rs
+++ b/pallets/nft/src/tests.rs
@@ -1,21 +1,16 @@
// Tests to be written here
use crate::mock::*;
-use crate::{AccessMode, ApprovePermissions, CollectionMode, Ownership, ChainLimits};
+use crate::{AccessMode, ApprovePermissions, CollectionMode, Ownership, ChainLimits, CreateItemData, NftItemType, CreateNftData, CreateFungibleData, CreateReFungibleData};
use frame_support::{assert_noop, assert_ok};
use frame_system::{ RawOrigin };
-// Use cases tests region
-// #region
-#[test]
-fn create_nft_item() {
- new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+fn default_collection_numbers_limit() -> u64 {
+ 10
+}
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
+fn default_limits() {
+ assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
+ collection_numbers_limit: default_collection_numbers_limit(),
account_token_ownership_limit: 10,
collections_admins_limit: 5,
custom_data_limit: 2048,
@@ -23,67 +18,86 @@
fungible_sponsor_transfer_timeout: 15,
refungible_sponsor_transfer_timeout: 15,
}));
+}
+
+fn default_nft_data() -> CreateItemData {
+ CreateItemData::NFT(CreateNftData { const_data: vec![1, 2, 3], variable_data: vec![3, 2, 1] })
+}
+
+fn default_fungible_data () -> CreateItemData {
+ CreateItemData::Fungible(CreateFungibleData { })
+}
- let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
+fn default_re_fungible_data () -> CreateItemData {
+ CreateItemData::ReFungible(CreateReFungibleData { const_data: vec![1, 2, 3], variable_data: vec![3, 2, 1] })
+}
+
+fn create_test_collection_for_owner(mode: &CollectionMode, owner: u64) -> u64 {
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+
+ let collection_id = TemplateModule::nextCollectionID();
+ let origin1 = Origin::signed(owner);
+ assert_ok!(TemplateModule::create_collection(
origin1.clone(),
col_name1.clone(),
col_desc1.clone(),
token_prefix1.clone(),
mode
));
- assert_eq!(TemplateModule::collection(1).owner, 1);
+ assert_eq!(TemplateModule::collection(collection_id).owner, owner);
+ return collection_id;
+}
+
+fn create_test_collection(mode: &CollectionMode) -> u64 {
+ return create_test_collection_for_owner(&mode, 1);
+}
- assert_ok!(TemplateModule::create_item(
+fn create_test_item(collection_id: u64, data: &CreateItemData) {
+ let origin1 = Origin::signed(1);
+ assert_ok!(TemplateModule::create_item(
origin1.clone(),
+ collection_id,
1,
- [1, 2, 3].to_vec(),
- 1
+ data.clone()
));
- assert_eq!(TemplateModule::nft_item_id(1, 1).data, [1, 2, 3].to_vec());
- });
+
}
+// Use cases tests region
+// #region
#[test]
-fn create_refungible_item() {
+fn create_nft_item() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::ReFungible(2000, 3);
+ default_limits();
+ let collection_id = create_test_collection(&CollectionMode::NFT);
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
+ let data = default_nft_data();
+ create_test_item(collection_id, &data);
+ assert_eq!(TemplateModule::nft_item_id(collection_id, 1).const_data, data.const_data);
+ assert_eq!(TemplateModule::nft_item_id(collection_id, 1).variable_data, data.variable_data);
+ });
+}
- let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
- assert_eq!(TemplateModule::collection(1).owner, 1);
+#[test]
+fn create_refungible_item() {
+ new_test_ext().execute_with(|| {
+ default_limits();
+ let collection_id = create_test_collection(&CollectionMode::ReFungible(3));
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [1, 2, 3].to_vec(),
- 1
- ));
+ let data = default_re_fungible_data();
+ create_test_item(collection_id, &data);
+ assert_eq!(
+ TemplateModule::refungible_item_id(collection_id, 1).const_data,
+ data.const_data
+ );
assert_eq!(
- TemplateModule::refungible_item_id(1, 1).data,
- [1, 2, 3].to_vec()
+ TemplateModule::refungible_item_id(collection_id, 1).variable_data,
+ data.variable_data
);
assert_eq!(
- TemplateModule::refungible_item_id(1, 1).owner[0],
+ TemplateModule::refungible_item_id(collection_id, 1).owner[0],
Ownership {
owner: 1,
fraction: 1000
@@ -95,38 +109,12 @@
#[test]
fn create_fungible_item() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::Fungible(3);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
+ let collection_id = create_test_collection(&CollectionMode::Fungible(3));
- let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
- assert_eq!(TemplateModule::collection(1).owner, 1);
+ let data = default_fungible_data();
+ create_test_item(collection_id, &data);
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [].to_vec(),
- 1
- ));
- assert_eq!(TemplateModule::fungible_item_id(1, 1).owner, 1);
+ assert_eq!(TemplateModule::fungible_item_id(collection_id, 1).owner, 1);
assert_eq!(TemplateModule::balance_count(1, 1), 1000);
assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
});
@@ -135,38 +123,16 @@
#[test]
fn transfer_fungible_item() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::Fungible(3);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::Fungible(3));
let origin1 = Origin::signed(1);
let origin2 = Origin::signed(2);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
- assert_eq!(TemplateModule::collection(1).owner, 1);
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [].to_vec(),
- 1
- ));
+ let data = default_fungible_data();
+ create_test_item(collection_id, &data);
+
assert_eq!(TemplateModule::fungible_item_id(1, 1).owner, 1);
assert_eq!(TemplateModule::balance_count(1, 1), 1000);
assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
@@ -203,44 +169,25 @@
#[test]
fn transfer_refungible_item() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::ReFungible(2000, 3);
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::ReFungible(3));
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
+ let data = default_re_fungible_data();
+ create_test_item(collection_id, &data);
let origin1 = Origin::signed(1);
let origin2 = Origin::signed(2);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
- assert_eq!(TemplateModule::collection(1).owner, 1);
-
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [1, 2, 3].to_vec(),
- 1
- ));
assert_eq!(
- TemplateModule::refungible_item_id(1, 1).data,
- [1, 2, 3].to_vec()
+ TemplateModule::refungible_item_id(collection_id, 1).const_data,
+ data.const_data
+ );
+ assert_eq!(
+ TemplateModule::refungible_item_id(collection_id, 1).variable_data,
+ data.variable_data
);
assert_eq!(
- TemplateModule::refungible_item_id(1, 1).owner[0],
+ TemplateModule::refungible_item_id(collection_id, 1).owner[0],
Ownership {
owner: 1,
fraction: 1000
@@ -310,38 +257,12 @@
#[test]
fn transfer_nft_item() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
- let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
- assert_eq!(TemplateModule::collection(1).owner, 1);
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [1, 2, 3].to_vec(),
- 1
- ));
- assert_eq!(TemplateModule::nft_item_id(1, 1).data, [1, 2, 3].to_vec());
+ let data = default_nft_data();
+ create_test_item(collection_id, &data);
assert_eq!(TemplateModule::balance_count(1, 1), 1);
assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
@@ -358,39 +279,16 @@
#[test]
fn nft_approve_and_transfer_from() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
+ let data = default_nft_data();
+ create_test_item(collection_id, &data);
let origin1 = Origin::signed(1);
let origin2 = Origin::signed(2);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
- assert_eq!(TemplateModule::collection(1).owner, 1);
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [1, 2, 3].to_vec(),
- 1
- ));
- assert_eq!(TemplateModule::nft_item_id(1, 1).data, [1, 2, 3].to_vec());
assert_eq!(TemplateModule::balance_count(1, 1), 1);
assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
@@ -436,49 +334,16 @@
#[test]
fn refungible_approve_and_transfer_from() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::ReFungible(2000, 3);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::ReFungible(3));
+
let origin1 = Origin::signed(1);
let origin2 = Origin::signed(2);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
- assert_eq!(TemplateModule::collection(1).owner, 1);
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [1, 2, 3].to_vec(),
- 1
- ));
- assert_eq!(
- TemplateModule::refungible_item_id(1, 1).data,
- [1, 2, 3].to_vec()
- );
- assert_eq!(
- TemplateModule::refungible_item_id(1, 1).owner[0],
- Ownership {
- owner: 1,
- fraction: 1000
- }
- );
+ let data = default_re_fungible_data();
+ create_test_item(collection_id, &data);
+
assert_eq!(TemplateModule::balance_count(1, 1), 1000);
assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
@@ -536,39 +401,16 @@
#[test]
fn fungible_approve_and_transfer_from() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::Fungible(3);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::Fungible(3));
+
+ let data = default_fungible_data();
+ create_test_item(collection_id, &data);
let origin1 = Origin::signed(1);
let origin2 = Origin::signed(2);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
- assert_eq!(TemplateModule::collection(1).owner, 1);
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [].to_vec(),
- 1
- ));
- assert_eq!(TemplateModule::fungible_item_id(1, 1).owner, 1);
assert_eq!(TemplateModule::balance_count(1, 1), 1000);
assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
@@ -642,104 +484,45 @@
#[test]
fn change_collection_owner() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
+
let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
assert_ok!(TemplateModule::change_collection_owner(
origin1.clone(),
- 1,
+ collection_id,
2
));
- assert_eq!(TemplateModule::collection(1).owner, 2);
+ assert_eq!(TemplateModule::collection(collection_id).owner, 2);
});
}
#[test]
fn destroy_collection() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
+
let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
- assert_ok!(TemplateModule::destroy_collection(origin1.clone(), 1));
+ assert_ok!(TemplateModule::destroy_collection(origin1.clone(), collection_id));
});
}
#[test]
fn burn_nft_item() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
- assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [1, 2, 3].to_vec(),
- 1
- ));
+ assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
+
+ let data = default_nft_data();
+ create_test_item(collection_id, &data);
- assert_eq!(TemplateModule::nft_item_id(1, 1).data, [1, 2, 3].to_vec());
-
// check balance (collection with id = 1, user id = 1)
assert_eq!(TemplateModule::balance_count(1, 1), 1);
@@ -757,36 +540,15 @@
#[test]
fn burn_fungible_item() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::Fungible(3);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::Fungible(3));
+
let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
- assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [].to_vec(),
- 1
- ));
+ assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
+
+ let data = default_fungible_data();
+ create_test_item(collection_id, &data);
// check balance (collection with id = 1, user id = 1)
assert_eq!(TemplateModule::balance_count(1, 1), 1000);
@@ -805,55 +567,28 @@
#[test]
fn burn_refungible_item() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::ReFungible(200, 3);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::ReFungible(3));
let origin1 = Origin::signed(1);
let origin2 = Origin::signed(2);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
assert_ok!(TemplateModule::set_mint_permission(
origin1.clone(),
- 1,
+ collection_id,
true
));
assert_ok!(TemplateModule::set_public_access_mode(
origin1.clone(),
- 1,
+ collection_id,
AccessMode::WhiteList
));
assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
- assert_ok!(TemplateModule::create_item(
- origin2.clone(),
- 1,
- [1, 2, 3].to_vec(),
- 1
- ));
-
- assert_eq!(
- TemplateModule::refungible_item_id(1, 1).data,
- [1, 2, 3].to_vec()
- );
+
+ let data = default_re_fungible_data();
+ create_test_item(collection_id, &data);
// check balance (collection with id = 1, user id = 2)
assert_eq!(TemplateModule::balance_count(1, 1), 1000);
@@ -872,110 +607,38 @@
#[test]
fn add_collection_admin() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
+ default_limits();
+
+ let collection1_id = create_test_collection_for_owner(&CollectionMode::NFT, 1);
+ create_test_collection_for_owner(&CollectionMode::NFT, 2);
+ create_test_collection_for_owner(&CollectionMode::NFT, 3);
+
let origin1 = Origin::signed(1);
- let origin2 = Origin::signed(2);
- let origin3 = Origin::signed(3);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode.clone()
- ));
- assert_ok!(TemplateModule::create_collection(
- origin2.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode.clone()
- ));
- assert_ok!(TemplateModule::create_collection(
- origin3.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode.clone()
- ));
-
- assert_eq!(TemplateModule::collection(1).owner, 1);
- assert_eq!(TemplateModule::collection(2).owner, 2);
- assert_eq!(TemplateModule::collection(3).owner, 3);
// collection admin
- assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
- assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 3));
+ assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, 2));
+ assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, 3));
- assert_eq!(TemplateModule::admin_list_collection(1).contains(&2), true);
- assert_eq!(TemplateModule::admin_list_collection(1).contains(&3), true);
+ assert_eq!(TemplateModule::admin_list_collection(collection1_id).contains(&2), true);
+ assert_eq!(TemplateModule::admin_list_collection(collection1_id).contains(&3), true);
});
}
#[test]
fn remove_collection_admin() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ default_limits();
+
+ let collection1_id = create_test_collection_for_owner(&CollectionMode::NFT, 1);
+ create_test_collection_for_owner(&CollectionMode::NFT, 2);
+ create_test_collection_for_owner(&CollectionMode::NFT, 3);
let origin1 = Origin::signed(1);
let origin2 = Origin::signed(2);
- let origin3 = Origin::signed(3);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode.clone()
- ));
- assert_ok!(TemplateModule::create_collection(
- origin2.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode.clone()
- ));
- assert_ok!(TemplateModule::create_collection(
- origin3.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode.clone()
- ));
-
- assert_eq!(TemplateModule::collection(1).owner, 1);
- assert_eq!(TemplateModule::collection(2).owner, 2);
- assert_eq!(TemplateModule::collection(3).owner, 3);
// collection admin
- assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
- assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 3));
+ assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, 2));
+ assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, 3));
assert_eq!(TemplateModule::admin_list_collection(1).contains(&2), true);
assert_eq!(TemplateModule::admin_list_collection(1).contains(&3), true);
@@ -993,125 +656,50 @@
#[test]
fn balance_of() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let nft_mode: CollectionMode = CollectionMode::NFT(2000);
- let furg_mode: CollectionMode = CollectionMode::Fungible(3);
- let refung_mode: CollectionMode = CollectionMode::ReFungible(2000, 3);
-
+ default_limits();
+
+ let nft_collection_id = create_test_collection(&CollectionMode::NFT);
+ let fungible_collection_id = create_test_collection(&CollectionMode::Fungible(3));
+ let re_fungible_collection_id = create_test_collection(&CollectionMode::ReFungible(3));
+
let origin1 = Origin::signed(1);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- nft_mode.clone()
- ));
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- furg_mode.clone()
- ));
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- refung_mode.clone()
- ));
-
- assert_eq!(TemplateModule::collection(1).owner, 1);
- assert_eq!(TemplateModule::collection(2).owner, 1);
- assert_eq!(TemplateModule::collection(3).owner, 1);
// check balance before
- assert_eq!(TemplateModule::balance_count(1, 1), 0);
- assert_eq!(TemplateModule::balance_count(2, 1), 0);
- assert_eq!(TemplateModule::balance_count(3, 1), 0);
+ assert_eq!(TemplateModule::balance_count(nft_collection_id, 1), 0);
+ assert_eq!(TemplateModule::balance_count(fungible_collection_id, 1), 0);
+ assert_eq!(TemplateModule::balance_count(re_fungible_collection_id, 1), 0);
- // create item
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [1, 1, 1].to_vec(),
- 1
- ));
-
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 2,
- [].to_vec(),
- 1
- ));
-
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 3,
- [1, 1, 1].to_vec(),
- 1
- ));
+ let nft_data = default_nft_data();
+ create_test_item(nft_collection_id, &nft_data);
+
+ let fungible_data = default_fungible_data();
+ create_test_item(fungible_collection_id, &fungible_data);
+
+ let re_fungible_data = default_re_fungible_data();
+ create_test_item(re_fungible_collection_id, &re_fungible_data);
// check balance (collection with id = 1, user id = 1)
- assert_eq!(TemplateModule::balance_count(1, 1), 1);
- assert_eq!(TemplateModule::balance_count(2, 1), 1000);
- assert_eq!(TemplateModule::balance_count(3, 1), 1000);
- assert_eq!(TemplateModule::nft_item_id(1, 1).owner, 1);
- assert_eq!(TemplateModule::fungible_item_id(2, 1).owner, 1);
- assert_eq!(TemplateModule::refungible_item_id(3, 1).owner[0].owner, 1);
+ assert_eq!(TemplateModule::balance_count(nft_collection_id, 1), 1);
+ assert_eq!(TemplateModule::balance_count(fungible_collection_id, 1), 1000);
+ assert_eq!(TemplateModule::balance_count(re_fungible_collection_id, 1), 1000);
+ assert_eq!(TemplateModule::nft_item_id(nft_collection_id, 1).owner, 1);
+ assert_eq!(TemplateModule::fungible_item_id(fungible_collection_id, 1).owner, 1);
+ assert_eq!(TemplateModule::refungible_item_id(re_fungible_collection_id, 1).owner[0].owner, 1);
});
}
#[test]
fn approve() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let nft_mode: CollectionMode = CollectionMode::NFT(2000);
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
+
+ let data = default_nft_data();
+ create_test_item(collection_id, &data);
+
let origin1 = Origin::signed(1);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- nft_mode.clone()
- ));
-
- assert_eq!(TemplateModule::collection(1).owner, 1);
-
- // create item
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [1, 1, 1].to_vec(),
- 1
- ));
-
+
// approve
assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
assert_eq!(TemplateModule::approved(1, (1, 1))[0].approved, 2);
@@ -1121,40 +709,14 @@
#[test]
fn transfer_from() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
let origin2 = Origin::signed(2);
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
-
- assert_eq!(TemplateModule::collection(1).owner, 1);
-
- // create item
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [1, 1, 1].to_vec(),
- 1
- ));
+ let data = default_nft_data();
+ create_test_item(collection_id, &data);
// approve
assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
@@ -1197,99 +759,41 @@
#[test]
fn owner_can_add_address_to_white_list() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
+
let origin1 = Origin::signed(1);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
-
- assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
- assert_eq!(TemplateModule::white_list(1)[0], 2);
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
+ assert_eq!(TemplateModule::white_list(collection_id)[0], 2);
});
}
#[test]
fn admin_can_add_address_to_white_list() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
let origin2 = Origin::signed(2);
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
-
- assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
- assert_ok!(TemplateModule::add_to_white_list(origin2.clone(), 1, 3));
- assert_eq!(TemplateModule::white_list(1)[0], 3);
+ assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
+ assert_ok!(TemplateModule::add_to_white_list(origin2.clone(), collection_id, 3));
+ assert_eq!(TemplateModule::white_list(collection_id)[0], 3);
});
}
#[test]
fn nonprivileged_user_cannot_add_address_to_white_list() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
- let origin1 = Origin::signed(1);
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
+
let origin2 = Origin::signed(2);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
-
assert_noop!(
- TemplateModule::add_to_white_list(origin2.clone(), 1, 3),
+ TemplateModule::add_to_white_list(origin2.clone(), collection_id, 3),
"You do not have permissions to modify this collection"
);
});
@@ -1298,17 +802,9 @@
#[test]
fn nobody_can_add_address_to_white_list_of_nonexisting_collection() {
new_test_ext().execute_with(|| {
+ default_limits();
+
let origin1 = Origin::signed(1);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
assert_noop!(
TemplateModule::add_to_white_list(origin1.clone(), 1, 2),
@@ -1320,33 +816,13 @@
#[test]
fn nobody_can_add_address_to_white_list_of_deleted_collection() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
- let origin1 = Origin::signed(1);
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
-
- assert_ok!(TemplateModule::destroy_collection(origin1.clone(), 1));
+ assert_ok!(TemplateModule::destroy_collection(origin1.clone(), collection_id));
assert_noop!(
- TemplateModule::add_to_white_list(origin1.clone(), 1, 2),
+ TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2),
"This collection does not exist"
);
});
@@ -1356,165 +832,80 @@
#[test]
fn address_is_already_added_to_white_list() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
-
- assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
- assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
- assert_eq!(TemplateModule::white_list(1)[0], 2);
- assert_eq!(TemplateModule::white_list(1).len(), 1);
+
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
+ assert_eq!(TemplateModule::white_list(collection_id)[0], 2);
+ assert_eq!(TemplateModule::white_list(collection_id).len(), 1);
});
}
#[test]
fn owner_can_remove_address_from_white_list() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
- let origin1 = Origin::signed(1);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
- assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+ let origin1 = Origin::signed(1);
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
assert_ok!(TemplateModule::remove_from_white_list(
origin1.clone(),
- 1,
+ collection_id,
2
));
- assert_eq!(TemplateModule::white_list(1).len(), 0);
+ assert_eq!(TemplateModule::white_list(collection_id).len(), 0);
});
}
#[test]
fn admin_can_remove_address_from_white_list() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
let origin2 = Origin::signed(2);
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
+ assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
-
- assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
-
- assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 3));
assert_ok!(TemplateModule::remove_from_white_list(
origin2.clone(),
- 1,
+ collection_id,
3
));
- assert_eq!(TemplateModule::white_list(1).len(), 0);
+ assert_eq!(TemplateModule::white_list(collection_id).len(), 0);
});
}
#[test]
fn nonprivileged_user_cannot_remove_address_from_white_list() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
let origin2 = Origin::signed(2);
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
-
- assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
assert_noop!(
- TemplateModule::remove_from_white_list(origin2.clone(), 1, 2),
+ TemplateModule::remove_from_white_list(origin2.clone(), collection_id, 2),
"You do not have permissions to modify this collection"
);
- assert_eq!(TemplateModule::white_list(1)[0], 2);
+ assert_eq!(TemplateModule::white_list(collection_id)[0], 2);
});
}
#[test]
fn nobody_can_remove_address_from_white_list_of_nonexisting_collection() {
new_test_ext().execute_with(|| {
+ default_limits();
let origin1 = Origin::signed(1);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
assert_noop!(
TemplateModule::remove_from_white_list(origin1.clone(), 1, 2),
@@ -1526,38 +917,19 @@
#[test]
fn nobody_can_remove_address_from_white_list_of_deleted_collection() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
let origin2 = Origin::signed(2);
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
-
- assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
- assert_ok!(TemplateModule::destroy_collection(origin1.clone(), 1));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
+ assert_ok!(TemplateModule::destroy_collection(origin1.clone(), collection_id));
assert_noop!(
- TemplateModule::remove_from_white_list(origin2.clone(), 1, 2),
+ TemplateModule::remove_from_white_list(origin2.clone(), collection_id, 2),
"This collection does not exist"
);
- assert_eq!(TemplateModule::white_list(1).len(), 0);
+ assert_eq!(TemplateModule::white_list(collection_id).len(), 0);
});
}
@@ -1565,42 +937,23 @@
#[test]
fn address_is_already_removed_from_white_list() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
-
- assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
assert_ok!(TemplateModule::remove_from_white_list(
origin1.clone(),
- 1,
+ collection_id,
2
));
assert_ok!(TemplateModule::remove_from_white_list(
origin1.clone(),
- 1,
+ collection_id,
2
));
- assert_eq!(TemplateModule::white_list(1).len(), 0);
+ assert_eq!(TemplateModule::white_list(collection_id).len(), 0);
});
}
@@ -1608,44 +961,21 @@
#[test]
fn white_list_test_1() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
- assert_eq!(TemplateModule::collection(1).owner, 1);
-
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [1, 2, 3].to_vec(),
- 1
- ));
+
+ let data = default_nft_data();
+ create_test_item(collection_id, &data);
assert_ok!(TemplateModule::set_public_access_mode(
origin1.clone(),
- 1,
+ collection_id,
AccessMode::WhiteList
));
- assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
assert_noop!(
TemplateModule::transfer(origin1.clone(), 3, 1, 1, 1),
@@ -1657,41 +987,17 @@
#[test]
fn white_list_test_2() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
- assert_eq!(TemplateModule::collection(1).owner, 1);
-
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [1, 2, 3].to_vec(),
- 1
- ));
+
+ let data = default_nft_data();
+ create_test_item(collection_id, &data);
assert_ok!(TemplateModule::set_public_access_mode(
origin1.clone(),
- 1,
+ collection_id,
AccessMode::WhiteList
));
assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
@@ -1718,41 +1024,18 @@
#[test]
fn white_list_test_3() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
- assert_eq!(TemplateModule::collection(1).owner, 1);
-
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [1, 2, 3].to_vec(),
- 1
- ));
+
+ let data = default_nft_data();
+ create_test_item(collection_id, &data);
assert_ok!(TemplateModule::set_public_access_mode(
origin1.clone(),
- 1,
+ collection_id,
AccessMode::WhiteList
));
assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
@@ -1767,45 +1050,22 @@
#[test]
fn white_list_test_4() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
- assert_eq!(TemplateModule::collection(1).owner, 1);
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [1, 2, 3].to_vec(),
- 1
- ));
+ let data = default_nft_data();
+ create_test_item(collection_id, &data);
assert_ok!(TemplateModule::set_public_access_mode(
origin1.clone(),
- 1,
+ collection_id,
AccessMode::WhiteList
));
- assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
- assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 1));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
// do approve
assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1));
@@ -1813,7 +1073,7 @@
assert_ok!(TemplateModule::remove_from_white_list(
origin1.clone(),
- 1,
+ collection_id,
2
));
@@ -1828,41 +1088,18 @@
#[test]
fn white_list_test_5() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
- assert_eq!(TemplateModule::collection(1).owner, 1);
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [1, 2, 3].to_vec(),
- 1
- ));
+ let data = default_nft_data();
+ create_test_item(collection_id, &data);
assert_ok!(TemplateModule::set_public_access_mode(
origin1.clone(),
- 1,
+ collection_id,
AccessMode::WhiteList
));
assert_noop!(
@@ -1876,32 +1113,14 @@
#[test]
fn white_list_test_6() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
assert_ok!(TemplateModule::set_public_access_mode(
origin1.clone(),
- 1,
+ collection_id,
AccessMode::WhiteList
));
@@ -1918,45 +1137,22 @@
#[test]
fn white_list_test_7() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
+ let data = default_nft_data();
+ create_test_item(collection_id, &data);
+
let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
- assert_eq!(TemplateModule::collection(1).owner, 1);
-
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [1, 2, 3].to_vec(),
- 1
- ));
assert_ok!(TemplateModule::set_public_access_mode(
origin1.clone(),
- 1,
+ collection_id,
AccessMode::WhiteList
));
- assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
- assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 1));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1));
});
@@ -1965,45 +1161,22 @@
#[test]
fn white_list_test_8() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
+ let data = default_nft_data();
+ create_test_item(collection_id, &data);
+
let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
- assert_eq!(TemplateModule::collection(1).owner, 1);
-
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [1, 2, 3].to_vec(),
- 1
- ));
assert_ok!(TemplateModule::set_public_access_mode(
origin1.clone(),
- 1,
+ collection_id,
AccessMode::WhiteList
));
- assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
- assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 1));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
// do approve
assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1));
@@ -2024,47 +1197,24 @@
#[test]
fn white_list_test_9() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
assert_ok!(TemplateModule::set_public_access_mode(
origin1.clone(),
- 1,
+ collection_id,
AccessMode::WhiteList
));
assert_ok!(TemplateModule::set_mint_permission(
origin1.clone(),
- 1,
+ collection_id,
false
));
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [1, 2, 3].to_vec(),
- 1
- ));
+ let data = default_nft_data();
+ create_test_item(collection_id, &data);
});
}
@@ -2072,49 +1222,31 @@
#[test]
fn white_list_test_10() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
let origin2 = Origin::signed(2);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
assert_ok!(TemplateModule::set_public_access_mode(
origin1.clone(),
- 1,
+ collection_id,
AccessMode::WhiteList
));
assert_ok!(TemplateModule::set_mint_permission(
origin1.clone(),
- 1,
+ collection_id,
false
));
- assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
+ assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
assert_ok!(TemplateModule::create_item(
origin2.clone(),
- 1,
- [1, 2, 3].to_vec(),
- 2
+ collection_id,
+ 2,
+ default_nft_data()
));
});
}
@@ -2123,45 +1255,27 @@
#[test]
fn white_list_test_11() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
let origin2 = Origin::signed(2);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
assert_ok!(TemplateModule::set_public_access_mode(
origin1.clone(),
- 1,
+ collection_id,
AccessMode::WhiteList
));
assert_ok!(TemplateModule::set_mint_permission(
origin1.clone(),
- 1,
+ collection_id,
false
));
- assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
assert_noop!(
- TemplateModule::create_item(origin2.clone(), 1, [1, 2, 3].to_vec(), 2),
+ TemplateModule::create_item(origin2.clone(), 1, vec![1, 2, 3], 2),
"Public minting is not allowed for this collection"
);
});
@@ -2171,44 +1285,26 @@
#[test]
fn white_list_test_12() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
let origin2 = Origin::signed(2);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
assert_ok!(TemplateModule::set_public_access_mode(
origin1.clone(),
- 1,
+ collection_id,
AccessMode::WhiteList
));
assert_ok!(TemplateModule::set_mint_permission(
origin1.clone(),
- 1,
+ collection_id,
false
));
assert_noop!(
- TemplateModule::create_item(origin2.clone(), 1, [1, 2, 3].to_vec(), 2),
+ TemplateModule::create_item(origin2.clone(), 1, vec![1, 2, 3], 2),
"Public minting is not allowed for this collection"
);
});
@@ -2218,47 +1314,25 @@
#[test]
fn white_list_test_13() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
assert_ok!(TemplateModule::set_public_access_mode(
origin1.clone(),
- 1,
+ collection_id,
AccessMode::WhiteList
));
assert_ok!(TemplateModule::set_mint_permission(
origin1.clone(),
- 1,
+ collection_id,
true
));
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [1, 2, 3].to_vec(),
- 1
- ));
+ let data = default_nft_data();
+ create_test_item(collection_id, &data);
});
}
@@ -2266,49 +1340,31 @@
#[test]
fn white_list_test_14() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
let origin2 = Origin::signed(2);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
assert_ok!(TemplateModule::set_public_access_mode(
origin1.clone(),
- 1,
+ collection_id,
AccessMode::WhiteList
));
assert_ok!(TemplateModule::set_mint_permission(
origin1.clone(),
- 1,
+ collection_id,
true
));
- assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
+ assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
assert_ok!(TemplateModule::create_item(
origin2.clone(),
1,
- [1, 2, 3].to_vec(),
- 2
+ 2,
+ default_nft_data()
));
});
}
@@ -2317,44 +1373,26 @@
#[test]
fn white_list_test_15() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
let origin2 = Origin::signed(2);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
assert_ok!(TemplateModule::set_public_access_mode(
origin1.clone(),
- 1,
+ collection_id,
AccessMode::WhiteList
));
assert_ok!(TemplateModule::set_mint_permission(
origin1.clone(),
- 1,
+ collection_id,
true
));
assert_noop!(
- TemplateModule::create_item(origin2.clone(), 1, [1, 2, 3].to_vec(), 2),
+ TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data()),
"Address is not in white list"
);
});
@@ -2364,48 +1402,30 @@
#[test]
fn white_list_test_16() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
let origin2 = Origin::signed(2);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
assert_ok!(TemplateModule::set_public_access_mode(
origin1.clone(),
- 1,
+ collection_id,
AccessMode::WhiteList
));
assert_ok!(TemplateModule::set_mint_permission(
origin1.clone(),
- 1,
+ collection_id,
true
));
- assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
assert_ok!(TemplateModule::create_item(
origin2.clone(),
1,
- [1, 2, 3].to_vec(),
- 2
+ 2,
+ default_nft_data()
));
});
}
@@ -2414,29 +1434,9 @@
#[test]
fn total_number_collections_bound() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
- let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
+ default_limits();
+
+ create_test_collection(&CollectionMode::NFT);
});
}
@@ -2444,32 +1444,12 @@
#[test]
fn total_number_collections_bound_neg() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
+ default_limits();
let origin1 = Origin::signed(1);
- for _ in 0..10 {
-
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode.clone()
- ));
+ for _ in 0..default_collection_numbers_limit() {
+ create_test_collection(&CollectionMode::NFT)
}
// 11-th collection in chain. Expects error
@@ -2487,43 +1467,13 @@
#[test]
fn owned_tokens_bound() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
- assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
- collection_numbers_limit: 10,
- account_token_ownership_limit: 10,
- collections_admins_limit: 5,
- custom_data_limit: 2048,
- nft_sponsor_transfer_timeout: 15,
- fungible_sponsor_transfer_timeout: 15,
- refungible_sponsor_transfer_timeout: 15,
- }));
-
- let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
-
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [1, 2, 3].to_vec(),
- 1
- ));
-
- assert_ok!(TemplateModule::create_item(
- origin1.clone(),
- 1,
- [1, 2, 3].to_vec(),
- 1
- ));
+ let data = default_nft_data();
+ create_test_item(collection_id, &data);
+ create_test_item(collection_id, &data);
});
}
@@ -2531,11 +1481,6 @@
#[test]
fn owned_tokens_bound_neg() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
collection_numbers_limit: 10,
account_token_ownership_limit: 1,
@@ -2545,28 +1490,18 @@
fungible_sponsor_transfer_timeout: 15,
refungible_sponsor_transfer_timeout: 15,
}));
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
+ let data = default_nft_data();
+ create_test_item(collection_id, &data);
- assert_ok!(TemplateModule::create_item(
+ assert_noop!(TemplateModule::create_item(
origin1.clone(),
1,
- [1, 2, 3].to_vec(),
- 1
- ));
-
- assert_noop!(TemplateModule::create_item(
- origin1.clone(),
1,
- [1, 2, 3].to_vec(),
- 1
+ data
), "Owned tokens by a single address bound exceeded");
});
}
@@ -2575,11 +1510,6 @@
#[test]
fn collection_admins_bound() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
collection_numbers_limit: 10,
account_token_ownership_limit: 10,
@@ -2589,18 +1519,13 @@
fungible_sponsor_transfer_timeout: 15,
refungible_sponsor_transfer_timeout: 15,
}));
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
-
- assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
- assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 3));
+
+ assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
+ assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 3));
});
}
@@ -2608,11 +1533,6 @@
#[test]
fn collection_admins_bound_neg() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
-
assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
collection_numbers_limit: 10,
account_token_ownership_limit: 1,
@@ -2622,78 +1542,167 @@
fungible_sponsor_transfer_timeout: 15,
refungible_sponsor_transfer_timeout: 15,
}));
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
- origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
- assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
- assert_noop!(TemplateModule::add_collection_admin(origin1.clone(), 1, 3), "Number of collection admins bound exceeded");
+ assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
+ assert_noop!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 3), "Number of collection admins bound exceeded");
});
}
-// Custom data size. Positive test
+// NFT custom data size. Negative test const_data.
#[test]
-fn custom_data_size_bound() {
+fn custom_data_size_nft_const_data_bound_neg() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
+ collection_numbers_limit: 10,
+ account_token_ownership_limit: 10,
+ collections_admins_limit: 5,
+ custom_data_limit: 2,
+ nft_sponsor_transfer_timeout: 15,
+ fungible_sponsor_transfer_timeout: 15,
+ refungible_sponsor_transfer_timeout: 15,
+ }));
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
+
+ let origin1 = Origin::signed(1);
+ let too_big_const_data = CreateItemData::NFT(CreateNftData{
+ const_data: vec![1, 2, 3, 4],
+ variable_data: vec![]
+ });
+
+ assert_noop!(TemplateModule::create_item(
+ origin1.clone(),
+ collection_id,
+ 1,
+ too_big_const_data
+ ), "const_data exceeded data limit: 2.");
+ });
+}
+// NFT custom data size. Negative test variable_data.
+#[test]
+fn custom_data_size_nft_variable_data_bound_neg() {
+ new_test_ext().execute_with(|| {
assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
collection_numbers_limit: 10,
account_token_ownership_limit: 10,
collections_admins_limit: 5,
- custom_data_limit: 2048,
+ custom_data_limit: 2,
nft_sponsor_transfer_timeout: 15,
fungible_sponsor_transfer_timeout: 15,
refungible_sponsor_transfer_timeout: 15,
}));
+ let collection_id = create_test_collection(&CollectionMode::NFT);
+
let origin1 = Origin::signed(1);
- assert_ok!(TemplateModule::create_collection(
+ let too_big_const_data = CreateItemData::NFT(CreateNftData{
+ const_data: vec![],
+ variable_data: vec![1, 2, 3, 4]
+ });
+
+ assert_noop!(TemplateModule::create_item(
origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ));
+ collection_id,
+ 1,
+ too_big_const_data
+ ), "variable_data exceeded data limit: 2.");
});
}
-// Custom data size. Negotive test
+// Re fungible custom data size. Negative test const_data.
#[test]
-fn custom_data_size_bound_neg() {
+fn custom_data_size_re_fungible_const_data_bound_neg() {
new_test_ext().execute_with(|| {
- let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
- let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
- let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
- let mode: CollectionMode = CollectionMode::NFT(2000);
+ assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
+ collection_numbers_limit: 10,
+ account_token_ownership_limit: 10,
+ collections_admins_limit: 5,
+ custom_data_limit: 2,
+ nft_sponsor_transfer_timeout: 15,
+ fungible_sponsor_transfer_timeout: 15,
+ refungible_sponsor_transfer_timeout: 15,
+ }));
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
+
+ let origin1 = Origin::signed(1);
+ let too_big_const_data = CreateItemData::NFT(CreateNftData{
+ const_data: vec![1, 2, 3, 4],
+ variable_data: vec![]
+ });
+
+ assert_noop!(TemplateModule::create_item(
+ origin1.clone(),
+ collection_id,
+ 1,
+ too_big_const_data
+ ), "const_data exceeded data limit: 2.");
+ });
+}
+// Re fungible custom data size. Negative test variable_data.
+#[test]
+fn custom_data_size_re_fungible_variable_data_bound_neg() {
+ new_test_ext().execute_with(|| {
assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {
collection_numbers_limit: 10,
account_token_ownership_limit: 10,
collections_admins_limit: 5,
- custom_data_limit: 200,
+ custom_data_limit: 2,
nft_sponsor_transfer_timeout: 15,
fungible_sponsor_transfer_timeout: 15,
refungible_sponsor_transfer_timeout: 15,
}));
+ let collection_id = create_test_collection(&CollectionMode::NFT);
+
let origin1 = Origin::signed(1);
- assert_noop!(TemplateModule::create_collection(
+ let too_big_const_data = CreateItemData::NFT(CreateNftData{
+ const_data: vec![],
+ variable_data: vec![1, 2, 3, 4]
+ });
+
+ assert_noop!(TemplateModule::create_item(
origin1.clone(),
- col_name1.clone(),
- col_desc1.clone(),
- token_prefix1.clone(),
- mode
- ), "Custom data size bound exceeded");
+ collection_id,
+ 1,
+ too_big_const_data
+ ), "variable_data exceeded data limit: 2.");
});
}
// #endregion
+
+#[test]
+fn set_const_on_chain_schema() {
+ new_test_ext().execute_with(|| {
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
+
+ let origin1 = Origin::signed(1);
+ assert_ok!(TemplateModule::set_const_on_chain_schema(origin1, collection_id, "test const on chain schema".to_vec()));
+
+ assert_eq!(TemplateModule::collection(collection_id).const_on_chain_schema, "test const on chain schema".to_vec());
+ assert_eq!(TemplateModule::collection(collection_id).variable_on_chain_schema, "".to_vec());
+ });
+}
+
+#[test]
+fn set_variable_on_chain_schema() {
+ new_test_ext().execute_with(|| {
+ default_limits();
+
+ let collection_id = create_test_collection(&CollectionMode::NFT);
+
+ let origin1 = Origin::signed(1);
+ assert_ok!(TemplateModule::set_variable_on_chain_schema(origin1, collection_id, "test variable on chain schema".to_vec()));
+
+ assert_eq!(TemplateModule::collection(collection_id).const_on_chain_schema, "".to_vec());
+ assert_eq!(TemplateModule::collection(collection_id).variable_on_chain_schema, "test variable on chain schema".to_vec());
+ });
+}
\ No newline at end of file
runtime/src/nft_weights.rsdiffbeforeafterboth--- a/runtime/src/nft_weights.rs
+++ b/runtime/src/nft_weights.rs
@@ -93,4 +93,19 @@
.saturating_add(DbWeight::get().reads(2 as Weight))
.saturating_add(DbWeight::get().writes(1 as Weight))
}
+ fn set_const_on_chain_schema() -> Weight {
+ (11_100_000 as Weight)
+ .saturating_add(DbWeight::get().reads(2 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn set_variable_on_chain_schema() -> Weight {
+ (11_100_000 as Weight)
+ .saturating_add(DbWeight::get().reads(2 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
+ fn set_variable_meta_data() -> Weight {
+ (17_500_000 as Weight)
+ .saturating_add(DbWeight::get().reads(2 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
}