drink-next 0.8.8

Minimal sufficient architecture that allows for a fully functional ink! contract development
#![allow(missing_docs)] // `construct_macro` doesn't allow doc comments for the runtime type.

/// Macro creating a minimal runtime with the given name. Optionally can take a chain extension
/// type as a second argument.
///
/// The new macro will automatically implement `drink::Runtime`.
#[macro_export]
macro_rules! create_minimal_runtime {
    ($name:ident) => {
        create_minimal_runtime!($name, ());
    };
    ($name:ident, $chain_extension: ty) => {
        // ------------ Put all the boilerplate into an auxiliary module -----------------------------------
        mod construct_runtime {

            // ------------ Bring some common types into the scope -----------------------------------------
            use $crate::frame_support::{
                construct_runtime,
                derive_impl,
                parameter_types,
                sp_runtime::{
                    testing::H256,
                    traits::Convert,
                    AccountId32, Perbill,
                },
                traits::{ConstBool, ConstU128, ConstU32, ConstU64, Currency, Randomness},
                weights::Weight,
            };
            use $crate::runtime::pallet_contracts_debugging::DrinkDebug;

            // ------------ Define the runtime type as a collection of pallets -----------------------------
            construct_runtime!(
                pub enum $name {
                    System: $crate::frame_system,
                    Balances: $crate::pallet_balances,
                    Timestamp: $crate::pallet_timestamp,
                    Contracts: $crate::pallet_contracts,
                }
            );

            // ------------ Configure pallet system --------------------------------------------------------
            #[derive_impl($crate::frame_system::config_preludes::SolochainDefaultConfig as $crate::frame_system::DefaultConfig)]
            impl $crate::frame_system::Config for $name {
                type Block = $crate::frame_system::mocking::MockBlockU32<$name>;
                type Version = ();
                type BlockHashCount = ConstU32<250>;
                type AccountData = $crate::pallet_balances::AccountData<<$name as $crate::pallet_balances::Config>::Balance>;
            }

            // ------------ Configure pallet balances ------------------------------------------------------
            impl $crate::pallet_balances::Config for $name {
                type RuntimeEvent = RuntimeEvent;
                type WeightInfo = ();
                type Balance = u128;
                type DustRemoval = ();
                type ExistentialDeposit = ConstU128<1>;
                type AccountStore = System;
                type ReserveIdentifier = [u8; 8];
                type FreezeIdentifier = ();
                type MaxLocks = ();
                type MaxReserves = ();
                type MaxHolds = ConstU32<1>;
                type MaxFreezes = ();
                type RuntimeHoldReason = RuntimeHoldReason;
                type RuntimeFreezeReason = RuntimeFreezeReason;
            }

            // ------------ Configure pallet timestamp -----------------------------------------------------
            impl $crate::pallet_timestamp::Config for $name {
                type Moment = u64;
                type OnTimestampSet = ();
                type MinimumPeriod = ConstU64<1>;
                type WeightInfo = ();
            }

            // ------------ Configure pallet contracts -----------------------------------------------------
            pub enum SandboxRandomness {}
            impl Randomness<H256, u32> for SandboxRandomness {
                fn random(_subject: &[u8]) -> (H256, u32) {
                    unreachable!("No randomness")
                }
            }

            type BalanceOf = <Balances as Currency<AccountId32>>::Balance;
            impl Convert<Weight, BalanceOf> for $name {
                fn convert(w: Weight) -> BalanceOf {
                    w.ref_time().into()
                }
            }

            parameter_types! {
                pub SandboxSchedule: $crate::pallet_contracts::Schedule<$name> = {
                    <$crate::pallet_contracts::Schedule<$name>>::default()
                };
                pub DeletionWeightLimit: Weight = Weight::zero();
                pub DefaultDepositLimit: BalanceOf = 10_000_000;
                pub CodeHashLockupDepositPercent: Perbill = Perbill::from_percent(0);
                pub MaxDelegateDependencies: u32 = 32;
            }

            impl $crate::pallet_contracts::Config for $name {
                type Time = Timestamp;
                type Randomness = SandboxRandomness;
                type Currency = Balances;
                type RuntimeEvent = RuntimeEvent;
                type RuntimeCall = RuntimeCall;
                type CallFilter = ();
                type WeightPrice = Self;
                type WeightInfo = ();
                type ChainExtension = $chain_extension;
                type Schedule = SandboxSchedule;
                type CallStack = [$crate::pallet_contracts::Frame<Self>; 5];
                type DepositPerByte = ConstU128<1>;
                type DepositPerItem = ConstU128<1>;
                type AddressGenerator = $crate::pallet_contracts::DefaultAddressGenerator;
                type MaxCodeLen = ConstU32<{ 123 * 1024 }>;
                type MaxStorageKeyLen = ConstU32<128>;
                type UnsafeUnstableInterface = ConstBool<false>;
                type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>;
                type Migrations = ();
                type DefaultDepositLimit = DefaultDepositLimit;
                type Debug = DrinkDebug;
                type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
                type MaxDelegateDependencies = MaxDelegateDependencies;
                type RuntimeHoldReason = RuntimeHoldReason;
                type Environment = ();
                type Xcm = ();
            }
        }

        // ------------ Export runtime type itself, pallets and useful types from the auxiliary module -----
        pub use construct_runtime::{
            $name, Balances, Contracts, PalletInfo, RuntimeCall, RuntimeEvent, RuntimeHoldReason,
            RuntimeOrigin, System, Timestamp,
        };

        impl_runtime!(super::$name, super::$name);
    };
}

#[macro_export]
macro_rules! impl_runtime {
    ($runtime:ty, $config:ty) => {
        mod runtime_runner {
            use std::time::SystemTime;
            use $crate::AccountId32;
            use $crate::runtime::{AccountIdFor, Runtime, RuntimeMetadataPrefixed};
            use $crate::frame_system::pallet_prelude::BlockNumberFor;
            use $crate::frame_support::{
                sp_runtime::{traits::Dispatchable, BuildStorage, Storage},
                traits::Hooks,
            };


            type System = $crate::frame_system::Pallet<$config>;
            type Contracts = $crate::pallet_contracts::Pallet<$config>;
            type Balances = $crate::pallet_balances::Pallet<$config>;
            type Timestamp = $crate::pallet_timestamp::Pallet<$config>;

            impl Runtime for $runtime {
                type Config = $config;
                fn initialize_storage(storage: &mut Storage) -> Result<(), String> {
                    const INITIAL_BALANCE: u128 = 1_000_000_000_000_000;
                    $crate::pallet_balances::GenesisConfig::<$config> {
                        balances: vec![(Self::default_actor(), INITIAL_BALANCE)],
                    }
                    .assimilate_storage(storage)
                }

                fn initialize_block(
                    height: $crate::frame_system::pallet_prelude::BlockNumberFor<Self::Config>,
                    parent_hash: <Self::Config as $crate::frame_system::Config>::Hash,
                ) -> Result<(), String> {
                    System::reset_events();
                    System::initialize(&height, &parent_hash, &Default::default());

                    Balances::on_initialize(height);
                    Timestamp::set_timestamp(
                        SystemTime::now()
                            .duration_since(SystemTime::UNIX_EPOCH)
                            .expect("Time went backwards")
                            .as_secs(),
                    );
                    Timestamp::on_initialize(height);
                    Contracts::on_initialize(height);

                    System::note_finished_initialize();

                    Ok(())
                }

                fn finalize_block(
                    height: BlockNumberFor<Self::Config>,
                ) -> Result<<Self::Config as $crate::frame_system::Config>::Hash, String> {
                    Contracts::on_finalize(height);
                    Timestamp::on_finalize(height);
                    Balances::on_finalize(height);

                    Ok(System::finalize().hash())
                }

                fn default_actor() -> AccountIdFor<Self::Config> {
                    AccountId32::new([1u8; 32])
                }

                fn get_metadata() -> RuntimeMetadataPrefixed {
                    <$config>::metadata()
                }

                fn convert_account_to_origin(
                    account: AccountIdFor<Self::Config>,
                ) -> <<$config as $crate::frame_system::Config>::RuntimeCall as Dispatchable>::RuntimeOrigin {
                    Some(account).into()
                }
            }
        }
    };
}

create_minimal_runtime!(MinimalRuntime);