difftreelog
Merge pull request #6 from usetech-llc/feature/white_list_nft_62-64
in: master
Feature/white list nft 62 64
4 files changed
README.mddiffbeforeafterboth--- a/README.md
+++ b/README.md
@@ -142,6 +142,12 @@
"enable_println": "bool",
"max_subject_len": "u32"
},
+ "AccessMode": {
+ "_enum": [
+ "Normal",
+ "WhiteList"
+ ]
+ },
"CollectionMode": {
"_enum": {
"Invalid": null,
@@ -181,12 +187,13 @@
"CollectionType": {
"Owner": "AccountId",
"Mode": "CollectionMode",
- "Access": "u8",
+ "Access": "AccessMode",
"DecimalPoints": "u32",
"Name": "Vec<u16>",
"Description": "Vec<u16>",
"TokenPrefix": "Vec<u8>",
"CustomDataSize": "u32",
+ "MintMode": "bool",
"OffchainSchema": "Vec<u8>",
"Sponsor": "AccountId",
"UnconfirmedSponsor": "AccountId"
@@ -196,4 +203,5 @@
"LookupSource": "AccountId",
"Weight": "u64"
}
+
```
\ No newline at end of file
pallets/nft/src/lib.rsdiffbeforeafterboth--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -97,6 +97,7 @@
pub description: Vec<u16>, // 256 include null escape char
pub token_prefix: Vec<u8>, // 16 include null escape char
pub custom_data_size: u32,
+ pub mint_mode: bool,
pub offchain_schema: Vec<u8>,
pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender
pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship
@@ -178,9 +179,6 @@
pub NftItemList get(fn nft_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;
pub FungibleItemList get(fn fungible_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;
pub ReFungibleItemList get(fn refungible_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;
-
- // Active vesting list
- // pub VestingList get(fn vesting): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => VestingItem<T::AccountId, T::Moment>;
/// Index list
pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;
@@ -209,7 +207,7 @@
fn on_initialize(now: T::BlockNumber) -> Weight {
- if ChainVersion::get() == 0
+ if ChainVersion::get() < 2
{
let value = NextCollectionID::get();
CreatedCollectionCount::put(value);
@@ -224,11 +222,11 @@
// @param customDataSz size of custom data in each collection item
// returns collection ID
#[weight = 0]
- pub fn create_collection( origin,
- collection_name: Vec<u16>,
- collection_description: Vec<u16>,
- token_prefix: Vec<u8>,
- mode: CollectionMode) -> DispatchResult {
+ pub fn create_collection(origin,
+ collection_name: Vec<u16>,
+ collection_description: Vec<u16>,
+ token_prefix: Vec<u8>,
+ mode: CollectionMode) -> DispatchResult {
// Anyone can create a collection
let who = ensure_signed(origin)?;
@@ -271,6 +269,7 @@
owner: who.clone(),
name: name,
mode: mode.clone(),
+ mint_mode: false,
access: AccessMode::Normal,
description: description,
decimal_points: decimal_points,
@@ -309,6 +308,73 @@
}
#[weight = 0]
+ pub fn add_to_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{
+
+ let sender = ensure_signed(origin)?;
+ Self::check_owner_or_admin_permissions(collection_id, sender)?;
+
+ let mut white_list_collection: Vec<T::AccountId>;
+ if <WhiteList<T>>::contains_key(collection_id) {
+ white_list_collection = <WhiteList<T>>::get(collection_id);
+ if !white_list_collection.contains(&address.clone())
+ {
+ white_list_collection.push(address.clone());
+ }
+ }
+ else {
+ white_list_collection = Vec::new();
+ white_list_collection.push(address.clone());
+ }
+
+ <WhiteList<T>>::insert(collection_id, white_list_collection);
+ Ok(())
+ }
+
+ #[weight = 0]
+ pub fn remove_from_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{
+
+ let sender = ensure_signed(origin)?;
+ Self::check_owner_or_admin_permissions(collection_id, sender)?;
+
+ if <WhiteList<T>>::contains_key(collection_id) {
+ let mut white_list_collection = <WhiteList<T>>::get(collection_id);
+ if white_list_collection.contains(&address.clone())
+ {
+ white_list_collection.retain(|i| *i != address.clone());
+ <WhiteList<T>>::insert(collection_id, white_list_collection);
+ }
+ }
+
+ Ok(())
+ }
+
+ #[weight = 0]
+ pub fn set_public_access_mode(origin, collection_id: u64, mode: AccessMode) -> DispatchResult
+ {
+ let sender = ensure_signed(origin)?;
+
+ Self::check_owner_permissions(collection_id, sender)?;
+ let mut target_collection = <Collection<T>>::get(collection_id);
+ target_collection.access = mode;
+ <Collection<T>>::insert(collection_id, target_collection);
+
+ Ok(())
+ }
+
+ #[weight = 0]
+ pub fn set_mint_permission(origin, collection_id: u64, mint_permission: bool) -> DispatchResult
+ {
+ let sender = ensure_signed(origin)?;
+
+ Self::check_owner_permissions(collection_id, sender)?;
+ let mut target_collection = <Collection<T>>::get(collection_id);
+ target_collection.mint_mode = mint_permission;
+ <Collection<T>>::insert(collection_id, target_collection);
+
+ Ok(())
+ }
+
+ #[weight = 0]
pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {
let sender = ensure_signed(origin)?;
@@ -405,9 +471,14 @@
pub fn create_item(origin, collection_id: u64, properties: Vec<u8>, owner: T::AccountId) -> DispatchResult {
let sender = ensure_signed(origin)?;
+ Self::collection_exists(collection_id)?;
let target_collection = <Collection<T>>::get(collection_id);
- Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;
+ if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {
+ ensure!(target_collection.mint_mode == true, "Collection is not in mint mode");
+ Self::check_white_list(collection_id, owner.clone())?;
+ }
+
match target_collection.mode
{
CollectionMode::NFT(_) => {
@@ -469,10 +540,13 @@
pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {
let sender = ensure_signed(origin)?;
+ Self::collection_exists(collection_id)?;
let item_owner = Self::is_item_owner(sender.clone(), collection_id, item_id);
if !item_owner
{
- Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;
+ if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {
+ Self::check_white_list(collection_id, sender.clone())?;
+ }
}
let target_collection = <Collection<T>>::get(collection_id);
@@ -494,11 +568,10 @@
pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {
let sender = ensure_signed(origin)?;
- ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id), "Only item owner can call transfer method");
-
+ Self::check_white_list(collection_id, sender.clone())?;
+ Self::check_white_list(collection_id, recipient.clone())?;
let target_collection = <Collection<T>>::get(collection_id);
- // TODO: implement other modes
match target_collection.mode
{
CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,
@@ -518,7 +591,10 @@
// amount param stub
let amount = 100000000;
- ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id), "Only item owner can call transfer method");
+ let item_owner = Self::is_item_owner(sender.clone(), collection_id, item_id);
+ if !item_owner {
+ Self::check_white_list(collection_id, approved.clone())?;
+ }
let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));
if list_exists {
@@ -545,22 +621,21 @@
let sender = ensure_signed(origin)?;
let approved_list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone()));
- if approved_list_exists
- {
- let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));
- let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());
- ensure!(opt_item.is_some(), "No approve found");
- ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");
- // remove approve
- let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))
- .into_iter().filter(|i| i.approved != sender.clone()).collect();
- <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);
- }
- else
- {
- Self::check_owner_or_admin_permissions(collection_id, sender)?;
- }
+ ensure!(approved_list_exists, "Only approved addresses can call this method");
+
+ Self::check_white_list(collection_id, from.clone())?;
+ Self::check_white_list(collection_id, recipient.clone())?;
+
+ let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));
+ let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());
+ ensure!(opt_item.is_some(), "No approve found");
+ ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");
+
+ // remove approve
+ let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))
+ .into_iter().filter(|i| i.approved != sender.clone()).collect();
+ <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);
let target_collection = <Collection<T>>::get(collection_id);
@@ -675,11 +750,7 @@
Ok(())
}
- fn burn_refungible_item(
- collection_id: u64,
- item_id: u64,
- owner: T::AccountId,
- ) -> DispatchResult {
+ fn burn_refungible_item(collection_id: u64, item_id: u64, owner: T::AccountId) -> DispatchResult {
ensure!(
<ReFungibleItemList<T>>::contains_key(collection_id, item_id),
"Item does not exists"
@@ -770,25 +841,27 @@
Ok(())
}
- fn check_owner_or_admin_permissions(
- collection_id: u64,
- subject: T::AccountId,
- ) -> DispatchResult {
- Self::collection_exists(collection_id)?;
+ fn is_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> bool {
let target_collection = <Collection<T>>::get(collection_id);
- let is_owner = subject == target_collection.owner;
-
- let no_perm_mes = "You do not have permissions to modify this collection";
+ let mut result: bool = subject == target_collection.owner;
let exists = <AdminList<T>>::contains_key(collection_id);
- if !is_owner {
- ensure!(exists, no_perm_mes);
- ensure!(
- <AdminList<T>>::get(collection_id).contains(&subject),
- no_perm_mes
- );
+ if !result & exists {
+ if <AdminList<T>>::get(collection_id).contains(&subject) {
+ result = true
+ }
}
+
+ result
+ }
+
+ fn check_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult {
+
+ Self::collection_exists(collection_id)?;
+ let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());
+
+ ensure!(result, "You do not have permissions to modify this collection");
Ok(())
}
@@ -812,6 +885,16 @@
}
}
+ fn check_white_list(collection_id: u64, address: T::AccountId) -> DispatchResult {
+
+ let mes = "Address is not in white list";
+ ensure!(<WhiteList<T>>::contains_key(collection_id), mes);
+ let wl = <WhiteList<T>>::get(collection_id);
+ ensure!(wl.contains(&address.clone()), mes);
+
+ Ok(())
+ }
+
fn transfer_fungible(
collection_id: u64,
item_id: u64,
@@ -819,6 +902,12 @@
owner: T::AccountId,
new_owner: T::AccountId,
) -> DispatchResult {
+
+ ensure!(
+ <FungibleItemList<T>>::contains_key(collection_id, item_id),
+ "Item not exists"
+ );
+
let full_item = <FungibleItemList<T>>::get(collection_id, item_id);
let amount = full_item.value;
@@ -903,6 +992,12 @@
owner: T::AccountId,
new_owner: T::AccountId,
) -> DispatchResult {
+
+ ensure!(
+ <ReFungibleItemList<T>>::contains_key(collection_id, item_id),
+ "Item not exists"
+ );
+
let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);
let item = full_item
.owner
@@ -983,6 +1078,12 @@
sender: T::AccountId,
new_owner: T::AccountId,
) -> DispatchResult {
+
+ ensure!(
+ <NftItemList<T>>::contains_key(collection_id, item_id),
+ "Item not exists"
+ );
+
let mut item = <NftItemList<T>>::get(collection_id, item_id);
ensure!(
pallets/nft/src/tests.rsdiffbeforeafterboth--- a/pallets/nft/src/tests.rs
+++ b/pallets/nft/src/tests.rs
@@ -1,6 +1,6 @@
// Tests to be written here
use crate::mock::*;
-use crate::{ApprovePermissions, CollectionMode, Ownership};
+use crate::{ApprovePermissions, CollectionMode, AccessMode, Ownership};
use frame_support::{assert_noop, assert_ok};
#[test]
@@ -321,10 +321,11 @@
assert_eq!(TemplateModule::balance_count(1, 1), 1);
assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
- assert_noop!(
- TemplateModule::transfer_from(origin2.clone(), 1, 3, 1, 1, 1),
- "You do not have permissions to modify this collection"
- );
+ assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
+ assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, 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(), 1, 3));
// do approve
assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
@@ -390,10 +391,11 @@
assert_eq!(TemplateModule::balance_count(1, 1), 1000);
assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
- assert_noop!(
- TemplateModule::transfer_from(origin2.clone(), 1, 3, 1, 1, 1),
- "You do not have permissions to modify this collection"
- );
+ assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
+ assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, 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(), 1, 3));
// do approve
assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
@@ -461,10 +463,11 @@
assert_eq!(TemplateModule::balance_count(1, 1), 1000);
assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
- assert_noop!(
- TemplateModule::transfer_from(origin2.clone(), 1, 3, 1, 1, 1),
- "You do not have permissions to modify this collection"
- );
+ assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
+ assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, 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(), 1, 3));
// do approve
assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
@@ -573,7 +576,6 @@
let mode: CollectionMode = CollectionMode::NFT(2000);
let origin1 = Origin::signed(1);
- let origin2 = Origin::signed(2);
assert_ok!(TemplateModule::create_collection(
origin1.clone(),
col_name1.clone(),
@@ -583,7 +585,7 @@
));
assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
assert_ok!(TemplateModule::create_item(
- origin2.clone(),
+ origin1.clone(),
1,
[1, 2, 3].to_vec(),
1
@@ -614,7 +616,6 @@
let mode: CollectionMode = CollectionMode::Fungible(3);
let origin1 = Origin::signed(1);
- let origin2 = Origin::signed(2);
assert_ok!(TemplateModule::create_collection(
origin1.clone(),
col_name1.clone(),
@@ -624,7 +625,7 @@
));
assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
assert_ok!(TemplateModule::create_item(
- origin2.clone(),
+ origin1.clone(),
1,
[].to_vec(),
1
@@ -661,6 +662,11 @@
token_prefix1.clone(),
mode
));
+
+ assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
+ assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, 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(),
@@ -928,6 +934,13 @@
// approve
assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
assert_eq!(TemplateModule::approved(1, (1, 1))[0].approved, 2);
+
+ assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
+ assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, 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(), 1, 3));
+
assert_ok!(TemplateModule::transfer_from(
origin2.clone(),
1,
runtime/src/lib.rsdiffbeforeafterboth1//! The Substrate Node Template runtime. This can be compiled with `#[no_std]`, ready for Wasm.23#![cfg_attr(not(feature = "std"), no_std)]4// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.5#![recursion_limit = "256"]67// Make the WASM binary available.8#[cfg(feature = "std")]9include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));1011use contracts_rpc_runtime_api::ContractExecResult;12use grandpa::fg_primitives;13use grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};14use sp_api::impl_runtime_apis;15use sp_consensus_aura::sr25519::AuthorityId as AuraId;16use sp_core::{crypto::KeyTypeId, OpaqueMetadata};17use sp_runtime::{18 create_runtime_str, generic, impl_opaque_keys,19 traits::{20 BlakeTwo256, Block as BlockT, IdentifyAccount, IdentityLookup, NumberFor, Saturating,21 Verify,22 },23 transaction_validity::{TransactionSource, TransactionValidity},24 ApplyExtrinsicResult, MultiSignature,25};26use sp_std::prelude::*;27#[cfg(feature = "std")]28use sp_version::NativeVersion;29use sp_version::RuntimeVersion;3031// A few exports that help ease life for downstream crates.32pub use balances::Call as BalancesCall;33pub use contracts::Schedule as ContractsSchedule;34pub use frame_support::{35 construct_runtime,36 dispatch::DispatchResult,37 parameter_types,38 traits::{39 Currency, ExistenceRequirement, Get, KeyOwnerProofSystem, OnUnbalanced, Randomness,40 WithdrawReason,41 },42 weights::{43 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},44 DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,45 WeightToFeePolynomial,46 },47 StorageValue,48};49#[cfg(any(feature = "std", test))]50pub use sp_runtime::BuildStorage;51use sp_runtime::Perbill;52use system::{self as system};5354pub use timestamp::Call as TimestampCall;5556/// Importing a nft pallet57pub use nft;5859/// An index to a block.60pub type BlockNumber = u32;6162/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.63pub type Signature = MultiSignature;6465/// Some way of identifying an account on the chain. We intentionally make it equivalent66/// to the public key of our transaction signing scheme.67pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;6869/// The type for looking up accounts. We don't expect more than 4 billion of them, but you70/// never know...71pub type AccountIndex = u32;7273/// Balance of an account.74pub type Balance = u128;7576/// Index of a transaction in the chain.77pub type Index = u32;7879/// A hash of some data used by the chain.80pub type Hash = sp_core::H256;8182/// Digest item type.83pub type DigestItem = generic::DigestItem<Hash>;8485/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know86/// the specifics of the runtime. They can then be made to be agnostic over specific formats87/// of data like extrinsics, allowing for them to continue syncing the network through upgrades88/// to even the core data structures.89pub mod opaque {90 use super::*;9192 pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;9394 /// Opaque block header type.95 pub type Header = generic::Header<BlockNumber, BlakeTwo256>;96 /// Opaque block type.97 pub type Block = generic::Block<Header, UncheckedExtrinsic>;98 /// Opaque block identifier type.99 pub type BlockId = generic::BlockId<Block>;100101 impl_opaque_keys! {102 pub struct SessionKeys {103 pub aura: Aura,104 pub grandpa: Grandpa,105 }106 }107}108109/// This runtime version.110pub const VERSION: RuntimeVersion = RuntimeVersion {111 spec_name: create_runtime_str!("nft"),112 impl_name: create_runtime_str!("nft"),113 authoring_version: 1,114 spec_version: 1,115 impl_version: 1,116 apis: RUNTIME_API_VERSIONS,117 transaction_version: 1,118};119120pub const MILLISECS_PER_BLOCK: u64 = 6000;121122pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;123124// These time units are defined in number of blocks.125pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);126pub const HOURS: BlockNumber = MINUTES * 60;127pub const DAYS: BlockNumber = HOURS * 24;128129/// The version information used to identify this runtime when compiled natively.130#[cfg(feature = "std")]131pub fn native_version() -> NativeVersion {132 NativeVersion {133 runtime_version: VERSION,134 can_author_with: Default::default(),135 }136}137138parameter_types! {139 pub const BlockHashCount: BlockNumber = 2400;140 /// We allow for 2 seconds of compute with a 6 second average block time.141 pub const MaximumBlockWeight: Weight = 2 * WEIGHT_PER_SECOND;142 pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);143 /// Assume 10% of weight for average on_initialize calls.144 pub MaximumExtrinsicWeight: Weight = AvailableBlockRatio::get()145 .saturating_sub(Perbill::from_percent(10)) * MaximumBlockWeight::get();146 pub const MaximumBlockLength: u32 = 5 * 1024 * 1024;147 pub const Version: RuntimeVersion = VERSION;148}149150impl system::Trait for Runtime {151 /// The basic call filter to use in dispatchable.152 type BaseCallFilter = ();153 /// The identifier used to distinguish between accounts.154 type AccountId = AccountId;155 /// The aggregated dispatch type that is available for extrinsics.156 type Call = Call;157 /// The lookup mechanism to get account ID from whatever is passed in dispatchers.158 type Lookup = IdentityLookup<AccountId>;159 /// The index type for storing how many extrinsics an account has signed.160 type Index = Index;161 /// The index type for blocks.162 type BlockNumber = BlockNumber;163 /// The type for hashing blocks and tries.164 type Hash = Hash;165 /// The hashing algorithm used.166 type Hashing = BlakeTwo256;167 /// The header type.168 type Header = generic::Header<BlockNumber, BlakeTwo256>;169 /// The ubiquitous event type.170 type Event = Event;171 /// The ubiquitous origin type.172 type Origin = Origin;173 /// Maximum number of block number to block hash mappings to keep (oldest pruned first).174 type BlockHashCount = BlockHashCount;175 /// Maximum weight of each block.176 type MaximumBlockWeight = MaximumBlockWeight;177 /// The weight of database operations that the runtime can invoke.178 type DbWeight = RocksDbWeight;179 /// The weight of the overhead invoked on the block import process, independent of the180 /// extrinsics included in that block.181 type BlockExecutionWeight = BlockExecutionWeight;182 /// The base weight of any extrinsic processed by the runtime, independent of the183 /// logic of that extrinsic. (Signature verification, nonce increment, fee, etc...)184 type ExtrinsicBaseWeight = ExtrinsicBaseWeight;185 /// The maximum weight that a single extrinsic of `Normal` dispatch class can have,186 /// idependent of the logic of that extrinsics. (Roughly max block weight - average on187 /// initialize cost).188 type MaximumExtrinsicWeight = MaximumExtrinsicWeight;189 /// Maximum size of all encoded transactions (in bytes) that are allowed in one block.190 type MaximumBlockLength = MaximumBlockLength;191 /// Portion of the block weight that is available to all normal transactions.192 type AvailableBlockRatio = AvailableBlockRatio;193 /// Version of the runtime.194 type Version = Version;195 /// Converts a module to the index of the module in `construct_runtime!`.196 /// This type is being generated by `construct_runtime!`.197 type ModuleToIndex = ModuleToIndex;198 /// What to do if a new account is created.199 type OnNewAccount = ();200 /// What to do if an account is fully reaped from the system.201 type OnKilledAccount = ();202 /// The data to be stored in an account.203 type AccountData = balances::AccountData<Balance>;204}205206impl aura::Trait for Runtime {207 type AuthorityId = AuraId;208}209210impl grandpa::Trait for Runtime {211 type Event = Event;212 type Call = Call;213214 type KeyOwnerProofSystem = ();215216 type KeyOwnerProof =217 <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(KeyTypeId, GrandpaId)>>::Proof;218219 type KeyOwnerIdentification = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(220 KeyTypeId,221 GrandpaId,222 )>>::IdentificationTuple;223224 type HandleEquivocation = ();225}226227parameter_types! {228 pub const MinimumPeriod: u64 = SLOT_DURATION / 2;229}230231impl timestamp::Trait for Runtime {232 /// A timestamp: milliseconds since the unix epoch.233 type Moment = u64;234 type OnTimestampSet = Aura;235 type MinimumPeriod = MinimumPeriod;236}237238parameter_types! {239 // pub const ExistentialDeposit: u128 = 500;240 pub const ExistentialDeposit: u128 = 0;241}242243impl balances::Trait for Runtime {244 /// The type for recording an account's balance.245 type Balance = Balance;246 /// The ubiquitous event type.247 type Event = Event;248 type DustRemoval = ();249 type ExistentialDeposit = ExistentialDeposit;250 type AccountStore = System;251}252253pub const MILLICENTS: Balance = 1_000_000_000;254pub const CENTS: Balance = 1_000 * MILLICENTS;255pub const DOLLARS: Balance = 100 * CENTS;256257parameter_types! {258 pub const TombstoneDeposit: Balance = 16 * MILLICENTS;259 pub const RentByteFee: Balance = 4 * MILLICENTS;260 pub const RentDepositOffset: Balance = 1000 * MILLICENTS;261 pub const SurchargeReward: Balance = 150 * MILLICENTS;262}263264impl contracts::Trait for Runtime {265 type Call = Call;266 type Time = Timestamp;267 type Randomness = RandomnessCollectiveFlip;268 type Currency = Balances;269 type Event = Event;270 type DetermineContractAddress = contracts::SimpleAddressDeterminer<Runtime>;271 type TrieIdGenerator = contracts::TrieIdFromParentCounter<Runtime>;272 type RentPayment = ();273 type SignedClaimHandicap = contracts::DefaultSignedClaimHandicap;274 type TombstoneDeposit = TombstoneDeposit;275 type StorageSizeOffset = contracts::DefaultStorageSizeOffset;276 type RentByteFee = RentByteFee;277 type RentDepositOffset = RentDepositOffset;278 type SurchargeReward = SurchargeReward;279 type MaxDepth = contracts::DefaultMaxDepth;280 type MaxValueSize = contracts::DefaultMaxValueSize;281 type WeightPrice = transaction_payment::Module<Self>;282}283284parameter_types! {285 pub const TransactionByteFee: Balance = 1;286}287288impl transaction_payment::Trait for Runtime {289 type Currency = balances::Module<Runtime>;290 type OnTransactionPayment = ();291 type TransactionByteFee = TransactionByteFee;292 type WeightToFee = IdentityFee<Balance>;293 type FeeMultiplierUpdate = ();294}295296impl sudo::Trait for Runtime {297 type Event = Event;298 type Call = Call;299}300301/// Used for the module nft in `./nft.rs`302impl nft::Trait for Runtime {303 type Event = Event;304}305306construct_runtime!(307 pub enum Runtime where308 Block = Block,309 NodeBlock = opaque::Block,310 UncheckedExtrinsic = UncheckedExtrinsic311 {312 System: system::{Module, Call, Config, Storage, Event<T>},313 RandomnessCollectiveFlip: randomness_collective_flip::{Module, Call, Storage},314 Contracts: contracts::{Module, Call, Config, Storage, Event<T>},315 Timestamp: timestamp::{Module, Call, Storage, Inherent},316 Aura: aura::{Module, Config<T>, Inherent(Timestamp)},317 Grandpa: grandpa::{Module, Call, Storage, Config, Event},318 Balances: balances::{Module, Call, Storage, Config<T>, Event<T>},319 TransactionPayment: transaction_payment::{Module, Storage},320 Sudo: sudo::{Module, Call, Config<T>, Storage, Event<T>},321 Nft: nft::{Module, Call, Storage, Event<T>},322 }323);324325/// The address format for describing accounts.326pub type Address = AccountId;327/// Block header type as expected by this runtime.328pub type Header = generic::Header<BlockNumber, BlakeTwo256>;329/// Block type as expected by this runtime.330pub type Block = generic::Block<Header, UncheckedExtrinsic>;331/// A Block signed with a Justification332pub type SignedBlock = generic::SignedBlock<Block>;333/// BlockId type as expected by this runtime.334pub type BlockId = generic::BlockId<Block>;335/// The SignedExtension to the basic transaction logic.336pub type SignedExtra = (337 system::CheckSpecVersion<Runtime>,338 system::CheckTxVersion<Runtime>,339 system::CheckGenesis<Runtime>,340 system::CheckEra<Runtime>,341 system::CheckNonce<Runtime>,342 system::CheckWeight<Runtime>,343 nft::ChargeTransactionPayment<Runtime>,344);345/// Unchecked extrinsic type as expected by this runtime.346pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;347/// Extrinsic type that has already been checked.348pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Call, SignedExtra>;349/// Executive: handles dispatch to the various modules.350pub type Executive =351 frame_executive::Executive<Runtime, Block, system::ChainContext<Runtime>, Runtime, AllModules>;352353impl_runtime_apis! {354355 impl contracts_rpc_runtime_api::ContractsApi<Block, AccountId, Balance, BlockNumber>356 for Runtime357 {358 fn call(359 origin: AccountId,360 dest: AccountId,361 value: Balance,362 gas_limit: u64,363 input_data: Vec<u8>,364 ) -> ContractExecResult {365 let exec_result =366 Contracts::bare_call(origin, dest.into(), value, gas_limit, input_data);367 match exec_result {368 Ok(v) => ContractExecResult::Success {369 status: v.status,370 data: v.data,371 },372 Err(_) => ContractExecResult::Error,373 }374 }375376 fn get_storage(377 address: AccountId,378 key: [u8; 32],379 ) -> contracts_primitives::GetStorageResult {380 Contracts::get_storage(address, key)381 }382383 fn rent_projection(384 address: AccountId,385 ) -> contracts_primitives::RentProjectionResult<BlockNumber> {386 Contracts::rent_projection(address)387 }388 }389390 impl sp_api::Core<Block> for Runtime {391 fn version() -> RuntimeVersion {392 VERSION393 }394395 fn execute_block(block: Block) {396 Executive::execute_block(block)397 }398399 fn initialize_block(header: &<Block as BlockT>::Header) {400 Executive::initialize_block(header)401 }402 }403404 impl sp_api::Metadata<Block> for Runtime {405 fn metadata() -> OpaqueMetadata {406 Runtime::metadata().into()407 }408 }409410 impl sp_block_builder::BlockBuilder<Block> for Runtime {411 fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {412 Executive::apply_extrinsic(extrinsic)413 }414415 fn finalize_block() -> <Block as BlockT>::Header {416 Executive::finalize_block()417 }418419 fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {420 data.create_extrinsics()421 }422423 fn check_inherents(424 block: Block,425 data: sp_inherents::InherentData,426 ) -> sp_inherents::CheckInherentsResult {427 data.check_extrinsics(&block)428 }429430 fn random_seed() -> <Block as BlockT>::Hash {431 RandomnessCollectiveFlip::random_seed()432 }433 }434435 impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {436 fn validate_transaction(437 source: TransactionSource,438 tx: <Block as BlockT>::Extrinsic,439 ) -> TransactionValidity {440 Executive::validate_transaction(source, tx)441 }442 }443444 impl sp_offchain::OffchainWorkerApi<Block> for Runtime {445 fn offchain_worker(header: &<Block as BlockT>::Header) {446 Executive::offchain_worker(header)447 }448 }449450 impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {451 fn slot_duration() -> u64 {452 Aura::slot_duration()453 }454455 fn authorities() -> Vec<AuraId> {456 Aura::authorities()457 }458 }459460 impl sp_session::SessionKeys<Block> for Runtime {461 fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {462 opaque::SessionKeys::generate(seed)463 }464465 fn decode_session_keys(466 encoded: Vec<u8>,467 ) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {468 opaque::SessionKeys::decode_into_raw_public_keys(&encoded)469 }470 }471472 impl fg_primitives::GrandpaApi<Block> for Runtime {473 fn grandpa_authorities() -> GrandpaAuthorityList {474 Grandpa::grandpa_authorities()475 }476477 fn submit_report_equivocation_extrinsic(478 _equivocation_proof: fg_primitives::EquivocationProof<479 <Block as BlockT>::Hash,480 NumberFor<Block>,481 >,482 _key_owner_proof: fg_primitives::OpaqueKeyOwnershipProof,483 ) -> Option<()> {484 None485 }486487 fn generate_key_ownership_proof(488 _set_id: fg_primitives::SetId,489 _authority_id: GrandpaId,490 ) -> Option<fg_primitives::OpaqueKeyOwnershipProof> {491 // NOTE: this is the only implementation possible since we've492 // defined our key owner proof type as a bottom type (i.e. a type493 // with no values).494 None495 }496 }497}1//! The Substrate Node Template runtime. This can be compiled with `#[no_std]`, ready for Wasm.23#![cfg_attr(not(feature = "std"), no_std)]4// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.5#![recursion_limit = "256"]67// Make the WASM binary available.8#[cfg(feature = "std")]9include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));1011use contracts_rpc_runtime_api::ContractExecResult;12use grandpa::fg_primitives;13use grandpa::{AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};14use sp_api::impl_runtime_apis;15use sp_consensus_aura::sr25519::AuthorityId as AuraId;16use sp_core::{crypto::KeyTypeId, OpaqueMetadata};17use sp_runtime::{18 create_runtime_str, generic, impl_opaque_keys,19 traits::{20 BlakeTwo256, Block as BlockT, IdentifyAccount, IdentityLookup, NumberFor, Saturating,21 Verify,22 },23 transaction_validity::{TransactionSource, TransactionValidity},24 ApplyExtrinsicResult, MultiSignature,25};26use sp_std::prelude::*;27#[cfg(feature = "std")]28use sp_version::NativeVersion;29use sp_version::RuntimeVersion;3031// A few exports that help ease life for downstream crates.32pub use balances::Call as BalancesCall;33pub use contracts::Schedule as ContractsSchedule;34pub use frame_support::{35 construct_runtime,36 dispatch::DispatchResult,37 parameter_types,38 traits::{39 Currency, ExistenceRequirement, Get, KeyOwnerProofSystem, OnUnbalanced, Randomness,40 WithdrawReason,41 },42 weights::{43 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},44 DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,45 WeightToFeePolynomial,46 },47 StorageValue,48};49#[cfg(any(feature = "std", test))]50pub use sp_runtime::BuildStorage;51use sp_runtime::Perbill;52use system::{self as system};5354pub use timestamp::Call as TimestampCall;5556/// Importing a nft pallet57pub use nft;5859/// An index to a block.60pub type BlockNumber = u32;6162/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.63pub type Signature = MultiSignature;6465/// Some way of identifying an account on the chain. We intentionally make it equivalent66/// to the public key of our transaction signing scheme.67pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;6869/// The type for looking up accounts. We don't expect more than 4 billion of them, but you70/// never know...71pub type AccountIndex = u32;7273/// Balance of an account.74pub type Balance = u128;7576/// Index of a transaction in the chain.77pub type Index = u32;7879/// A hash of some data used by the chain.80pub type Hash = sp_core::H256;8182/// Digest item type.83pub type DigestItem = generic::DigestItem<Hash>;8485/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know86/// the specifics of the runtime. They can then be made to be agnostic over specific formats87/// of data like extrinsics, allowing for them to continue syncing the network through upgrades88/// to even the core data structures.89pub mod opaque {90 use super::*;9192 pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;9394 /// Opaque block header type.95 pub type Header = generic::Header<BlockNumber, BlakeTwo256>;96 /// Opaque block type.97 pub type Block = generic::Block<Header, UncheckedExtrinsic>;98 /// Opaque block identifier type.99 pub type BlockId = generic::BlockId<Block>;100101 impl_opaque_keys! {102 pub struct SessionKeys {103 pub aura: Aura,104 pub grandpa: Grandpa,105 }106 }107}108109/// This runtime version.110pub const VERSION: RuntimeVersion = RuntimeVersion {111 spec_name: create_runtime_str!("nft"),112 impl_name: create_runtime_str!("nft"),113 authoring_version: 1,114 spec_version: 2,115 impl_version: 1,116 apis: RUNTIME_API_VERSIONS,117 transaction_version: 1,118};119120pub const MILLISECS_PER_BLOCK: u64 = 6000;121122pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;123124// These time units are defined in number of blocks.125pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);126pub const HOURS: BlockNumber = MINUTES * 60;127pub const DAYS: BlockNumber = HOURS * 24;128129/// The version information used to identify this runtime when compiled natively.130#[cfg(feature = "std")]131pub fn native_version() -> NativeVersion {132 NativeVersion {133 runtime_version: VERSION,134 can_author_with: Default::default(),135 }136}137138parameter_types! {139 pub const BlockHashCount: BlockNumber = 2400;140 /// We allow for 2 seconds of compute with a 6 second average block time.141 pub const MaximumBlockWeight: Weight = 2 * WEIGHT_PER_SECOND;142 pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);143 /// Assume 10% of weight for average on_initialize calls.144 pub MaximumExtrinsicWeight: Weight = AvailableBlockRatio::get()145 .saturating_sub(Perbill::from_percent(10)) * MaximumBlockWeight::get();146 pub const MaximumBlockLength: u32 = 5 * 1024 * 1024;147 pub const Version: RuntimeVersion = VERSION;148}149150impl system::Trait for Runtime {151 /// The basic call filter to use in dispatchable.152 type BaseCallFilter = ();153 /// The identifier used to distinguish between accounts.154 type AccountId = AccountId;155 /// The aggregated dispatch type that is available for extrinsics.156 type Call = Call;157 /// The lookup mechanism to get account ID from whatever is passed in dispatchers.158 type Lookup = IdentityLookup<AccountId>;159 /// The index type for storing how many extrinsics an account has signed.160 type Index = Index;161 /// The index type for blocks.162 type BlockNumber = BlockNumber;163 /// The type for hashing blocks and tries.164 type Hash = Hash;165 /// The hashing algorithm used.166 type Hashing = BlakeTwo256;167 /// The header type.168 type Header = generic::Header<BlockNumber, BlakeTwo256>;169 /// The ubiquitous event type.170 type Event = Event;171 /// The ubiquitous origin type.172 type Origin = Origin;173 /// Maximum number of block number to block hash mappings to keep (oldest pruned first).174 type BlockHashCount = BlockHashCount;175 /// Maximum weight of each block.176 type MaximumBlockWeight = MaximumBlockWeight;177 /// The weight of database operations that the runtime can invoke.178 type DbWeight = RocksDbWeight;179 /// The weight of the overhead invoked on the block import process, independent of the180 /// extrinsics included in that block.181 type BlockExecutionWeight = BlockExecutionWeight;182 /// The base weight of any extrinsic processed by the runtime, independent of the183 /// logic of that extrinsic. (Signature verification, nonce increment, fee, etc...)184 type ExtrinsicBaseWeight = ExtrinsicBaseWeight;185 /// The maximum weight that a single extrinsic of `Normal` dispatch class can have,186 /// idependent of the logic of that extrinsics. (Roughly max block weight - average on187 /// initialize cost).188 type MaximumExtrinsicWeight = MaximumExtrinsicWeight;189 /// Maximum size of all encoded transactions (in bytes) that are allowed in one block.190 type MaximumBlockLength = MaximumBlockLength;191 /// Portion of the block weight that is available to all normal transactions.192 type AvailableBlockRatio = AvailableBlockRatio;193 /// Version of the runtime.194 type Version = Version;195 /// Converts a module to the index of the module in `construct_runtime!`.196 /// This type is being generated by `construct_runtime!`.197 type ModuleToIndex = ModuleToIndex;198 /// What to do if a new account is created.199 type OnNewAccount = ();200 /// What to do if an account is fully reaped from the system.201 type OnKilledAccount = ();202 /// The data to be stored in an account.203 type AccountData = balances::AccountData<Balance>;204}205206impl aura::Trait for Runtime {207 type AuthorityId = AuraId;208}209210impl grandpa::Trait for Runtime {211 type Event = Event;212 type Call = Call;213214 type KeyOwnerProofSystem = ();215216 type KeyOwnerProof =217 <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(KeyTypeId, GrandpaId)>>::Proof;218219 type KeyOwnerIdentification = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(220 KeyTypeId,221 GrandpaId,222 )>>::IdentificationTuple;223224 type HandleEquivocation = ();225}226227parameter_types! {228 pub const MinimumPeriod: u64 = SLOT_DURATION / 2;229}230231impl timestamp::Trait for Runtime {232 /// A timestamp: milliseconds since the unix epoch.233 type Moment = u64;234 type OnTimestampSet = Aura;235 type MinimumPeriod = MinimumPeriod;236}237238parameter_types! {239 // pub const ExistentialDeposit: u128 = 500;240 pub const ExistentialDeposit: u128 = 0;241}242243impl balances::Trait for Runtime {244 /// The type for recording an account's balance.245 type Balance = Balance;246 /// The ubiquitous event type.247 type Event = Event;248 type DustRemoval = ();249 type ExistentialDeposit = ExistentialDeposit;250 type AccountStore = System;251}252253pub const MILLICENTS: Balance = 1_000_000_000;254pub const CENTS: Balance = 1_000 * MILLICENTS;255pub const DOLLARS: Balance = 100 * CENTS;256257parameter_types! {258 pub const TombstoneDeposit: Balance = 16 * MILLICENTS;259 pub const RentByteFee: Balance = 4 * MILLICENTS;260 pub const RentDepositOffset: Balance = 1000 * MILLICENTS;261 pub const SurchargeReward: Balance = 150 * MILLICENTS;262}263264impl contracts::Trait for Runtime {265 type Call = Call;266 type Time = Timestamp;267 type Randomness = RandomnessCollectiveFlip;268 type Currency = Balances;269 type Event = Event;270 type DetermineContractAddress = contracts::SimpleAddressDeterminer<Runtime>;271 type TrieIdGenerator = contracts::TrieIdFromParentCounter<Runtime>;272 type RentPayment = ();273 type SignedClaimHandicap = contracts::DefaultSignedClaimHandicap;274 type TombstoneDeposit = TombstoneDeposit;275 type StorageSizeOffset = contracts::DefaultStorageSizeOffset;276 type RentByteFee = RentByteFee;277 type RentDepositOffset = RentDepositOffset;278 type SurchargeReward = SurchargeReward;279 type MaxDepth = contracts::DefaultMaxDepth;280 type MaxValueSize = contracts::DefaultMaxValueSize;281 type WeightPrice = transaction_payment::Module<Self>;282}283284parameter_types! {285 pub const TransactionByteFee: Balance = 1;286}287288impl transaction_payment::Trait for Runtime {289 type Currency = balances::Module<Runtime>;290 type OnTransactionPayment = ();291 type TransactionByteFee = TransactionByteFee;292 type WeightToFee = IdentityFee<Balance>;293 type FeeMultiplierUpdate = ();294}295296impl sudo::Trait for Runtime {297 type Event = Event;298 type Call = Call;299}300301/// Used for the module nft in `./nft.rs`302impl nft::Trait for Runtime {303 type Event = Event;304}305306construct_runtime!(307 pub enum Runtime where308 Block = Block,309 NodeBlock = opaque::Block,310 UncheckedExtrinsic = UncheckedExtrinsic311 {312 System: system::{Module, Call, Config, Storage, Event<T>},313 RandomnessCollectiveFlip: randomness_collective_flip::{Module, Call, Storage},314 Contracts: contracts::{Module, Call, Config, Storage, Event<T>},315 Timestamp: timestamp::{Module, Call, Storage, Inherent},316 Aura: aura::{Module, Config<T>, Inherent(Timestamp)},317 Grandpa: grandpa::{Module, Call, Storage, Config, Event},318 Balances: balances::{Module, Call, Storage, Config<T>, Event<T>},319 TransactionPayment: transaction_payment::{Module, Storage},320 Sudo: sudo::{Module, Call, Config<T>, Storage, Event<T>},321 Nft: nft::{Module, Call, Storage, Event<T>},322 }323);324325/// The address format for describing accounts.326pub type Address = AccountId;327/// Block header type as expected by this runtime.328pub type Header = generic::Header<BlockNumber, BlakeTwo256>;329/// Block type as expected by this runtime.330pub type Block = generic::Block<Header, UncheckedExtrinsic>;331/// A Block signed with a Justification332pub type SignedBlock = generic::SignedBlock<Block>;333/// BlockId type as expected by this runtime.334pub type BlockId = generic::BlockId<Block>;335/// The SignedExtension to the basic transaction logic.336pub type SignedExtra = (337 system::CheckSpecVersion<Runtime>,338 system::CheckTxVersion<Runtime>,339 system::CheckGenesis<Runtime>,340 system::CheckEra<Runtime>,341 system::CheckNonce<Runtime>,342 system::CheckWeight<Runtime>,343 nft::ChargeTransactionPayment<Runtime>,344);345/// Unchecked extrinsic type as expected by this runtime.346pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;347/// Extrinsic type that has already been checked.348pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Call, SignedExtra>;349/// Executive: handles dispatch to the various modules.350pub type Executive =351 frame_executive::Executive<Runtime, Block, system::ChainContext<Runtime>, Runtime, AllModules>;352353impl_runtime_apis! {354355 impl contracts_rpc_runtime_api::ContractsApi<Block, AccountId, Balance, BlockNumber>356 for Runtime357 {358 fn call(359 origin: AccountId,360 dest: AccountId,361 value: Balance,362 gas_limit: u64,363 input_data: Vec<u8>,364 ) -> ContractExecResult {365 let exec_result =366 Contracts::bare_call(origin, dest.into(), value, gas_limit, input_data);367 match exec_result {368 Ok(v) => ContractExecResult::Success {369 status: v.status,370 data: v.data,371 },372 Err(_) => ContractExecResult::Error,373 }374 }375376 fn get_storage(377 address: AccountId,378 key: [u8; 32],379 ) -> contracts_primitives::GetStorageResult {380 Contracts::get_storage(address, key)381 }382383 fn rent_projection(384 address: AccountId,385 ) -> contracts_primitives::RentProjectionResult<BlockNumber> {386 Contracts::rent_projection(address)387 }388 }389390 impl sp_api::Core<Block> for Runtime {391 fn version() -> RuntimeVersion {392 VERSION393 }394395 fn execute_block(block: Block) {396 Executive::execute_block(block)397 }398399 fn initialize_block(header: &<Block as BlockT>::Header) {400 Executive::initialize_block(header)401 }402 }403404 impl sp_api::Metadata<Block> for Runtime {405 fn metadata() -> OpaqueMetadata {406 Runtime::metadata().into()407 }408 }409410 impl sp_block_builder::BlockBuilder<Block> for Runtime {411 fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {412 Executive::apply_extrinsic(extrinsic)413 }414415 fn finalize_block() -> <Block as BlockT>::Header {416 Executive::finalize_block()417 }418419 fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {420 data.create_extrinsics()421 }422423 fn check_inherents(424 block: Block,425 data: sp_inherents::InherentData,426 ) -> sp_inherents::CheckInherentsResult {427 data.check_extrinsics(&block)428 }429430 fn random_seed() -> <Block as BlockT>::Hash {431 RandomnessCollectiveFlip::random_seed()432 }433 }434435 impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {436 fn validate_transaction(437 source: TransactionSource,438 tx: <Block as BlockT>::Extrinsic,439 ) -> TransactionValidity {440 Executive::validate_transaction(source, tx)441 }442 }443444 impl sp_offchain::OffchainWorkerApi<Block> for Runtime {445 fn offchain_worker(header: &<Block as BlockT>::Header) {446 Executive::offchain_worker(header)447 }448 }449450 impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {451 fn slot_duration() -> u64 {452 Aura::slot_duration()453 }454455 fn authorities() -> Vec<AuraId> {456 Aura::authorities()457 }458 }459460 impl sp_session::SessionKeys<Block> for Runtime {461 fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {462 opaque::SessionKeys::generate(seed)463 }464465 fn decode_session_keys(466 encoded: Vec<u8>,467 ) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {468 opaque::SessionKeys::decode_into_raw_public_keys(&encoded)469 }470 }471472 impl fg_primitives::GrandpaApi<Block> for Runtime {473 fn grandpa_authorities() -> GrandpaAuthorityList {474 Grandpa::grandpa_authorities()475 }476477 fn submit_report_equivocation_extrinsic(478 _equivocation_proof: fg_primitives::EquivocationProof<479 <Block as BlockT>::Hash,480 NumberFor<Block>,481 >,482 _key_owner_proof: fg_primitives::OpaqueKeyOwnershipProof,483 ) -> Option<()> {484 None485 }486487 fn generate_key_ownership_proof(488 _set_id: fg_primitives::SetId,489 _authority_id: GrandpaId,490 ) -> Option<fg_primitives::OpaqueKeyOwnershipProof> {491 // NOTE: this is the only implementation possible since we've492 // defined our key owner proof type as a bottom type (i.e. a type493 // with no values).494 None495 }496 }497}