From 8b6ec0a2fe298f72010bec00c20840ebed7fbb98 Mon Sep 17 00:00:00 2001 From: aidan46 Date: Fri, 15 Nov 2024 15:46:31 +0800 Subject: [PATCH 1/6] feat: Add faucet pallet Add a faucet pallet with a drip function that can be used once a day per account and drips 10UNITs. --- Cargo.lock | 17 ++++++ Cargo.toml | 2 + pallets/faucet/Cargo.toml | 36 +++++++++++++ pallets/faucet/src/lib.rs | 106 +++++++++++++++++++++++++++++++++++++ pallets/faucet/src/mock.rs | 97 +++++++++++++++++++++++++++++++++ pallets/faucet/src/test.rs | 72 +++++++++++++++++++++++++ runtime/Cargo.toml | 1 + runtime/src/configs/mod.rs | 12 +++++ runtime/src/lib.rs | 4 ++ 9 files changed, 347 insertions(+) create mode 100644 pallets/faucet/Cargo.toml create mode 100644 pallets/faucet/src/lib.rs create mode 100644 pallets/faucet/src/mock.rs create mode 100644 pallets/faucet/src/test.rs diff --git a/Cargo.lock b/Cargo.lock index 04d743e8..5306e030 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8279,6 +8279,22 @@ dependencies = [ "sp-staking", ] +[[package]] +name = "pallet-faucet" +version = "0.0.0" +dependencies = [ + "env_logger 0.11.5", + "frame-support", + "frame-system", + "log", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-runtime 39.0.0", +] + [[package]] name = "pallet-grandpa" version = "37.0.0" @@ -9689,6 +9705,7 @@ dependencies = [ "pallet-authorship", "pallet-balances", "pallet-collator-selection", + "pallet-faucet", "pallet-insecure-randomness-collective-flip", "pallet-market", "pallet-message-queue", diff --git a/Cargo.toml b/Cargo.toml index a80f02b0..4468bd03 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ members = [ "lib/polka-storage-proofs", "maat", "node", + "pallets/faucet", "pallets/market", "pallets/proofs", "pallets/randomness", @@ -127,6 +128,7 @@ zombienet-support = "=0.2.14" # Local cli-primitives = { path = "primitives/cli" } mater = { path = "storage/mater" } +pallet-faucet = { path = "pallets/faucet", default-features = false } pallet-market = { path = "pallets/market", default-features = false } pallet-proofs = { path = "pallets/proofs", default-features = false } pallet-randomness = { path = "pallets/randomness", default-features = false } diff --git a/pallets/faucet/Cargo.toml b/pallets/faucet/Cargo.toml new file mode 100644 index 00000000..ab8a3ec1 --- /dev/null +++ b/pallets/faucet/Cargo.toml @@ -0,0 +1,36 @@ +[package] +authors.workspace = true +description = "exposes a drip function for getting funds on testnet" +edition.workspace = true +homepage.workspace = true +license-file.workspace = true +name = "pallet-faucet" +publish = false +repository.workspace = true +version = "0.0.0" + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { workspace = true, default-features = false, features = ["derive"] } +frame-support = { workspace = true, default-features = false } +frame-system = { workspace = true, default-features = false } +log = { workspace = true } +pallet-balances = { workspace = true, default-features = false } +scale-info = { workspace = true, default-features = false, features = ["derive"] } + +[dev-dependencies] +env_logger = { workspace = true } +sp-core = { workspace = true, default-features = false } +sp-io = { workspace = true } +sp-runtime = { workspace = true, default-features = false } + +[features] +default = ["std"] +runtime-benchmarks = ["frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks"] +std = ["codec/std", "frame-support/std", "frame-system/std", "pallet-balances/std", "scale-info/std", "sp-core/std", "sp-io/std", "sp-runtime/std"] +try-runtime = ["frame-support/try-runtime", "frame-system/try-runtime", "sp-runtime/try-runtime"] diff --git a/pallets/faucet/src/lib.rs b/pallets/faucet/src/lib.rs new file mode 100644 index 00000000..73488ece --- /dev/null +++ b/pallets/faucet/src/lib.rs @@ -0,0 +1,106 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +pub use pallet::*; + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod test; + +#[frame_support::pallet(dev_mode)] +pub mod pallet { + use frame_support::{ + pallet_prelude::*, + traits::{Currency, ReservableCurrency}, + }; + use frame_system::{ensure_none, pallet_prelude::*}; + + /// Allows to extract Balance of an account via the Config::Currency associated type. + /// BalanceOf is a sophisticated way of getting an u128. + pub type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + + #[pallet::pallet] + #[pallet::without_storage_info] // Allows to define storage items without fixed size + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + /// Because this pallet emits events, it depends on the runtime's definition of an event. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// The currency mechanism. + type Currency: ReservableCurrency; + + /// The amount that is dispensed in planck's + #[pallet::constant] + type FaucetAmount: Get>; + + /// How often an account can use the drip function (1 day on testnet) + #[pallet::constant] + type FaucetDelay: Get>; + } + + /// By default pallet do no allow for unsigned transactions. + /// Implementing this trait for the faucet Pallet allows unsigned extrinsics to be called. + /// There is no complicated implementation needed (like checking the call type) + /// because there is only one transaction in this pallet + #[pallet::validate_unsigned] + impl ValidateUnsigned for Pallet { + type Call = Call; + + fn validate_unsigned( + _source: TransactionSource, + _call: &Self::Call, + ) -> TransactionValidity { + let current_block = >::block_number(); + ValidTransaction::with_tag_prefix("pallet-faucet") + .and_provides(current_block) + .build() + } + } + + /// Keeps track of when accounts last used the drip function. + #[pallet::storage] + #[pallet::getter(fn drips)] + pub type Drips = StorageMap<_, _, T::AccountId, BlockNumberFor>; + + #[pallet::event] + #[pallet::generate_deposit(fn deposit_event)] + pub enum Event { + /// Emitted when an account uses the drip function successfully. + Dripped { + who: T::AccountId, + when: BlockNumberFor, + }, + } + + #[pallet::error] + pub enum Error { + /// Emitted when an account tries to call the drip function more than 1x in 24 hours. + FaucetUsedRecently, + } + + #[pallet::call] + impl Pallet { + pub fn drip(origin: OriginFor, account: T::AccountId) -> DispatchResult { + let _ = ensure_none(origin)?; + let current_block = >::block_number(); + if let Some(faucet_block) = Self::drips(&account) { + ensure!(current_block >= (faucet_block + T::FaucetDelay::get()), { + log::error!("{account:?} has recently used the faucet"); + Error::::FaucetUsedRecently + }); + } + log::info!("Dripping {:?} to {account:?}", T::FaucetAmount::get()); + let imbalance = T::Currency::deposit_creating(&account, T::FaucetAmount::get()); + drop(imbalance); + Drips::::insert(account.clone(), current_block); + Self::deposit_event(Event::::Dripped { + who: account, + when: current_block, + }); + Ok(()) + } + } +} diff --git a/pallets/faucet/src/mock.rs b/pallets/faucet/src/mock.rs new file mode 100644 index 00000000..bc77ad3c --- /dev/null +++ b/pallets/faucet/src/mock.rs @@ -0,0 +1,97 @@ +use frame_support::{derive_impl, parameter_types, traits::Hooks}; +use frame_system::{self as system}; +use sp_core::Pair; +use sp_runtime::{ + traits::{IdentifyAccount, IdentityLookup, Verify}, + AccountId32, BuildStorage, MultiSignature, MultiSigner, +}; + +use crate::{self as pallet_faucet, BalanceOf}; + +pub const ALICE: &'static str = "//Alice"; + +type Block = frame_system::mocking::MockBlock; +type BlockNumber = u64; + +frame_support::construct_runtime!( + pub enum Test { + System: frame_system, + Balances: pallet_balances, + Faucet: pallet_faucet, + } +); + +pub type Signature = MultiSignature; +pub type AccountPublic = ::Signer; +pub type AccountId = ::AccountId; + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] +impl frame_system::Config for Test { + type Block = Block; + type AccountData = pallet_balances::AccountData; + type AccountId = AccountId; + type Lookup = IdentityLookup; +} + +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] +impl pallet_balances::Config for Test { + type AccountStore = System; +} + +parameter_types! { + pub const FaucetAmount: BalanceOf = 10_000_000_000_000; + pub const FaucetDelay: BlockNumber = 1; +} + +impl crate::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type FaucetAmount = FaucetAmount; + type FaucetDelay = FaucetDelay; +} + +pub fn key_pair(name: &str) -> sp_core::sr25519::Pair { + sp_core::sr25519::Pair::from_string(name, None).unwrap() +} + +pub fn account(name: &str) -> AccountId32 { + let user_pair = key_pair(name); + let signer = MultiSigner::Sr25519(user_pair.public()); + signer.into_account() +} + +pub fn events() -> Vec { + let evt = System::events() + .into_iter() + .map(|evt| evt.event) + .collect::>(); + System::reset_events(); + evt +} + +/// Run until a particular block. +/// +/// Stolen't from: +pub fn run_to_block(n: u64) { + while System::block_number() < n { + if System::block_number() > 1 { + System::on_finalize(System::block_number()); + } + + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + } +} + +/// Build genesis storage according to the mock runtime. +pub fn new_test_ext() -> sp_io::TestExternalities { + let _ = env_logger::try_init(); + let t = system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} diff --git a/pallets/faucet/src/test.rs b/pallets/faucet/src/test.rs new file mode 100644 index 00000000..69ee7794 --- /dev/null +++ b/pallets/faucet/src/test.rs @@ -0,0 +1,72 @@ +use frame_support::{assert_err, assert_ok}; +use frame_system::Event as SystemEvent; +use pallet_balances::Event as BalanceEvent; + +use crate::{mock::*, Error, Event}; + +#[test] +fn drip() { + new_test_ext().execute_with(|| { + let account = account::(ALICE); + assert_ok!(Faucet::drip(RuntimeOrigin::none(), account.clone())); + + // The initial drip should create the account + assert_eq!( + events(), + [ + RuntimeEvent::Balances(BalanceEvent::Deposit { + who: account.clone(), + amount: ::FaucetAmount::get() + }), + RuntimeEvent::System(SystemEvent::NewAccount { + account: account.clone() + }), + RuntimeEvent::Balances(BalanceEvent::Endowed { + account: account.clone(), + free_balance: ::FaucetAmount::get() + }), + RuntimeEvent::Faucet(Event::Dripped { + who: account.clone(), + when: System::block_number() + }) + ] + ); + + assert_eq!( + Balances::free_balance(account.clone()), + ::FaucetAmount::get() + ); + + // Check that dripping at the same block is blocked + assert_err!( + Faucet::drip(RuntimeOrigin::none(), account.clone()), + Error::::FaucetUsedRecently + ); + + // Run to block_number + faucet_delay + run_to_block(System::block_number() + ::FaucetDelay::get()); + + // Rerun drip, should be successful + assert_ok!(Faucet::drip(RuntimeOrigin::none(), account.clone())); + + // Expecting less events because no new account is created + assert_eq!( + events(), + [ + RuntimeEvent::Balances(BalanceEvent::Deposit { + who: account.clone(), + amount: ::FaucetAmount::get() + }), + RuntimeEvent::Faucet(Event::Dripped { + who: account.clone(), + when: System::block_number() + }) + ] + ); + + assert_eq!( + Balances::free_balance(account.clone()), + ::FaucetAmount::get() * 2 + ); + }); +} diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index d42d1674..869fff92 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -20,6 +20,7 @@ substrate-wasm-builder = { workspace = true, optional = true } [dependencies] # Local Pallets +pallet-faucet = { workspace = true, default-features = false } pallet-market = { workspace = true, default-features = false } pallet-proofs = { workspace = true, default-features = false } pallet-randomness = { workspace = true, default-features = false } diff --git a/runtime/src/configs/mod.rs b/runtime/src/configs/mod.rs index 727d5794..1dd03605 100644 --- a/runtime/src/configs/mod.rs +++ b/runtime/src/configs/mod.rs @@ -368,6 +368,10 @@ parameter_types! { // Randomness pallet pub const CleanupInterval: BlockNumber = DAYS; pub const SeedAgeLimit: BlockNumber = 30 * DAYS; + + // Faucet pallet + pub const FaucetAmount: Balance = 10_000_000_000_000; + pub const FaucetDelay: BlockNumber = DAYS; } impl pallet_storage_provider::Config for Runtime { @@ -418,6 +422,14 @@ impl pallet_proofs::Config for Runtime { type RuntimeEvent = RuntimeEvent; } +#[cfg(feature = "testnet")] +impl pallet_faucet::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type FaucetAmount = FaucetAmount; + type FaucetDelay = FaucetDelay; +} + /// Config for insecure randomness impl pallet_insecure_randomness_collective_flip::Config for Runtime {} diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index c3bc7c71..d39f0953 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -306,6 +306,10 @@ mod runtime { pub type Proofs = pallet_proofs; #[runtime::pallet_index(37)] pub type Randomness = pallet_randomness; + + #[cfg(feature = "testnet")] + #[runtime::pallet_index(38)] + pub type Faucet = pallet_faucet; } #[docify::export(register_validate_block)] From 3a11fd4aa470670bf3382e59f2762d0813e7be52 Mon Sep 17 00:00:00 2001 From: aidan46 Date: Mon, 18 Nov 2024 17:17:34 +0800 Subject: [PATCH 2/6] fix: Separate testnet runtime --- runtime/src/lib.rs | 73 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index d39f0953..d9685d17 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -238,6 +238,7 @@ pub fn native_version() -> NativeVersion { } // Create the runtime by composing the FRAME pallets that were previously configured. +#[cfg(not(feature = "testnet"))] #[frame_support::runtime] mod runtime { #[runtime::runtime] @@ -306,8 +307,78 @@ mod runtime { pub type Proofs = pallet_proofs; #[runtime::pallet_index(37)] pub type Randomness = pallet_randomness; +} + +// Create the runtime by composing the FRAME pallets that were previously configured. +#[cfg(feature = "testnet")] +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive( + RuntimeCall, + RuntimeEvent, + RuntimeError, + RuntimeOrigin, + RuntimeFreezeReason, + RuntimeHoldReason, + RuntimeSlashReason, + RuntimeLockId, + RuntimeTask + )] + pub struct Runtime; + + #[runtime::pallet_index(0)] + pub type System = frame_system; + #[runtime::pallet_index(1)] + pub type ParachainSystem = cumulus_pallet_parachain_system; + #[runtime::pallet_index(2)] + pub type Timestamp = pallet_timestamp; + #[runtime::pallet_index(3)] + pub type ParachainInfo = parachain_info; + // Temporary. Will be removed after we switch to babe + #[runtime::pallet_index(4)] + pub type RandomnessSource = pallet_insecure_randomness_collective_flip; + + // Monetary stuff. + #[runtime::pallet_index(10)] + pub type Balances = pallet_balances; + #[runtime::pallet_index(11)] + pub type TransactionPayment = pallet_transaction_payment; + + // Governance + #[runtime::pallet_index(15)] + pub type Sudo = pallet_sudo; + + // Collator support. The order of these 4 are important and shall not change. + #[runtime::pallet_index(20)] + pub type Authorship = pallet_authorship; + #[runtime::pallet_index(21)] + pub type CollatorSelection = pallet_collator_selection; + #[runtime::pallet_index(22)] + pub type Session = pallet_session; + #[runtime::pallet_index(23)] + pub type Aura = pallet_aura; + #[runtime::pallet_index(24)] + pub type AuraExt = cumulus_pallet_aura_ext; - #[cfg(feature = "testnet")] + // XCM helpers. + #[runtime::pallet_index(30)] + pub type XcmpQueue = cumulus_pallet_xcmp_queue; + #[runtime::pallet_index(31)] + pub type PolkadotXcm = pallet_xcm; + #[runtime::pallet_index(32)] + pub type CumulusXcm = cumulus_pallet_xcm; + #[runtime::pallet_index(33)] + pub type MessageQueue = pallet_message_queue; + + #[runtime::pallet_index(34)] + pub type StorageProvider = pallet_storage_provider::pallet; + #[runtime::pallet_index(35)] + pub type Market = pallet_market; + #[runtime::pallet_index(36)] + pub type Proofs = pallet_proofs; + #[runtime::pallet_index(37)] + pub type Randomness = pallet_randomness; #[runtime::pallet_index(38)] pub type Faucet = pallet_faucet; } From 3e3b040d8491bf00d40d228c00b998858e85dc92 Mon Sep 17 00:00:00 2001 From: aidan46 Date: Mon, 18 Nov 2024 17:40:09 +0800 Subject: [PATCH 3/6] fix: Remove without_storage_info in faucet pallet --- pallets/faucet/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pallets/faucet/src/lib.rs b/pallets/faucet/src/lib.rs index 73488ece..d7abffdc 100644 --- a/pallets/faucet/src/lib.rs +++ b/pallets/faucet/src/lib.rs @@ -21,7 +21,6 @@ pub mod pallet { <::Currency as Currency<::AccountId>>::Balance; #[pallet::pallet] - #[pallet::without_storage_info] // Allows to define storage items without fixed size pub struct Pallet(_); #[pallet::config] From acfae79cbdbf7818966cdbefac3df60c9603e277 Mon Sep 17 00:00:00 2001 From: aidan46 Date: Mon, 18 Nov 2024 17:52:17 +0800 Subject: [PATCH 4/6] fix: Rename faucet constants --- pallets/faucet/src/lib.rs | 10 +++++----- pallets/faucet/src/mock.rs | 8 ++++---- pallets/faucet/src/test.rs | 12 ++++++------ runtime/src/configs/mod.rs | 8 ++++---- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/pallets/faucet/src/lib.rs b/pallets/faucet/src/lib.rs index d7abffdc..588da41a 100644 --- a/pallets/faucet/src/lib.rs +++ b/pallets/faucet/src/lib.rs @@ -33,11 +33,11 @@ pub mod pallet { /// The amount that is dispensed in planck's #[pallet::constant] - type FaucetAmount: Get>; + type FaucetDripAmount: Get>; /// How often an account can use the drip function (1 day on testnet) #[pallet::constant] - type FaucetDelay: Get>; + type FaucetDripDelay: Get>; } /// By default pallet do no allow for unsigned transactions. @@ -86,13 +86,13 @@ pub mod pallet { let _ = ensure_none(origin)?; let current_block = >::block_number(); if let Some(faucet_block) = Self::drips(&account) { - ensure!(current_block >= (faucet_block + T::FaucetDelay::get()), { + ensure!(current_block >= (faucet_block + T::FaucetDripDelay::get()), { log::error!("{account:?} has recently used the faucet"); Error::::FaucetUsedRecently }); } - log::info!("Dripping {:?} to {account:?}", T::FaucetAmount::get()); - let imbalance = T::Currency::deposit_creating(&account, T::FaucetAmount::get()); + log::info!("Dripping {:?} to {account:?}", T::FaucetDripAmount::get()); + let imbalance = T::Currency::deposit_creating(&account, T::FaucetDripAmount::get()); drop(imbalance); Drips::::insert(account.clone(), current_block); Self::deposit_event(Event::::Dripped { diff --git a/pallets/faucet/src/mock.rs b/pallets/faucet/src/mock.rs index bc77ad3c..641fbb45 100644 --- a/pallets/faucet/src/mock.rs +++ b/pallets/faucet/src/mock.rs @@ -39,15 +39,15 @@ impl pallet_balances::Config for Test { } parameter_types! { - pub const FaucetAmount: BalanceOf = 10_000_000_000_000; - pub const FaucetDelay: BlockNumber = 1; + pub const FaucetDripAmount: BalanceOf = 10_000_000_000_000; + pub const FaucetDripDelay: BlockNumber = 1; } impl crate::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type FaucetAmount = FaucetAmount; - type FaucetDelay = FaucetDelay; + type FaucetDripAmount = FaucetDripAmount; + type FaucetDripDelay = FaucetDripDelay; } pub fn key_pair(name: &str) -> sp_core::sr25519::Pair { diff --git a/pallets/faucet/src/test.rs b/pallets/faucet/src/test.rs index 69ee7794..37ef6efe 100644 --- a/pallets/faucet/src/test.rs +++ b/pallets/faucet/src/test.rs @@ -16,14 +16,14 @@ fn drip() { [ RuntimeEvent::Balances(BalanceEvent::Deposit { who: account.clone(), - amount: ::FaucetAmount::get() + amount: ::FaucetDripAmount::get() }), RuntimeEvent::System(SystemEvent::NewAccount { account: account.clone() }), RuntimeEvent::Balances(BalanceEvent::Endowed { account: account.clone(), - free_balance: ::FaucetAmount::get() + free_balance: ::FaucetDripAmount::get() }), RuntimeEvent::Faucet(Event::Dripped { who: account.clone(), @@ -34,7 +34,7 @@ fn drip() { assert_eq!( Balances::free_balance(account.clone()), - ::FaucetAmount::get() + ::FaucetDripAmount::get() ); // Check that dripping at the same block is blocked @@ -44,7 +44,7 @@ fn drip() { ); // Run to block_number + faucet_delay - run_to_block(System::block_number() + ::FaucetDelay::get()); + run_to_block(System::block_number() + ::FaucetDripDelay::get()); // Rerun drip, should be successful assert_ok!(Faucet::drip(RuntimeOrigin::none(), account.clone())); @@ -55,7 +55,7 @@ fn drip() { [ RuntimeEvent::Balances(BalanceEvent::Deposit { who: account.clone(), - amount: ::FaucetAmount::get() + amount: ::FaucetDripAmount::get() }), RuntimeEvent::Faucet(Event::Dripped { who: account.clone(), @@ -66,7 +66,7 @@ fn drip() { assert_eq!( Balances::free_balance(account.clone()), - ::FaucetAmount::get() * 2 + ::FaucetDripAmount::get() * 2 ); }); } diff --git a/runtime/src/configs/mod.rs b/runtime/src/configs/mod.rs index 1dd03605..55694e3c 100644 --- a/runtime/src/configs/mod.rs +++ b/runtime/src/configs/mod.rs @@ -370,8 +370,8 @@ parameter_types! { pub const SeedAgeLimit: BlockNumber = 30 * DAYS; // Faucet pallet - pub const FaucetAmount: Balance = 10_000_000_000_000; - pub const FaucetDelay: BlockNumber = DAYS; + pub const FaucetDripAmount: Balance = 10_000_000_000_000; + pub const FaucetDripDelay: BlockNumber = DAYS; } impl pallet_storage_provider::Config for Runtime { @@ -426,8 +426,8 @@ impl pallet_proofs::Config for Runtime { impl pallet_faucet::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type FaucetAmount = FaucetAmount; - type FaucetDelay = FaucetDelay; + type FaucetDripAmount = FaucetDripAmount; + type FaucetDripDelay = FaucetDripDelay; } /// Config for insecure randomness From d8ffedd681ba2d493b884d287bf26d280e51f63a Mon Sep 17 00:00:00 2001 From: aidan46 Date: Tue, 19 Nov 2024 12:57:07 +0800 Subject: [PATCH 5/6] fix: Change token issuance logic --- pallets/faucet/src/lib.rs | 19 ++++++++++++------- pallets/faucet/src/test.rs | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/pallets/faucet/src/lib.rs b/pallets/faucet/src/lib.rs index 588da41a..e3ffaef5 100644 --- a/pallets/faucet/src/lib.rs +++ b/pallets/faucet/src/lib.rs @@ -82,18 +82,23 @@ pub mod pallet { #[pallet::call] impl Pallet { + #[pallet::weight((Weight::zero(), Pays::No))] pub fn drip(origin: OriginFor, account: T::AccountId) -> DispatchResult { - let _ = ensure_none(origin)?; + ensure_none(origin)?; let current_block = >::block_number(); if let Some(faucet_block) = Self::drips(&account) { - ensure!(current_block >= (faucet_block + T::FaucetDripDelay::get()), { - log::error!("{account:?} has recently used the faucet"); - Error::::FaucetUsedRecently - }); + ensure!( + current_block >= (faucet_block + T::FaucetDripDelay::get()), + { + log::error!("{account:?} has recently used the faucet"); + Error::::FaucetUsedRecently + } + ); } log::info!("Dripping {:?} to {account:?}", T::FaucetDripAmount::get()); - let imbalance = T::Currency::deposit_creating(&account, T::FaucetDripAmount::get()); - drop(imbalance); + // Infallible https://docs.rs/frame-support/latest/frame_support/traits/tokens/currency/trait.Currency.html#tymethod.issue + let imbalance = T::Currency::issue(T::FaucetDripAmount::get()); + T::Currency::resolve_creating(&account, imbalance); Drips::::insert(account.clone(), current_block); Self::deposit_event(Event::::Dripped { who: account, diff --git a/pallets/faucet/src/test.rs b/pallets/faucet/src/test.rs index 37ef6efe..2bd710f2 100644 --- a/pallets/faucet/src/test.rs +++ b/pallets/faucet/src/test.rs @@ -65,7 +65,7 @@ fn drip() { ); assert_eq!( - Balances::free_balance(account.clone()), + Balances::free_balance(account), ::FaucetDripAmount::get() * 2 ); }); From c0750b89ccb6bde52b5dd67c66817260c8241729 Mon Sep 17 00:00:00 2001 From: aidan46 Date: Tue, 19 Nov 2024 13:04:17 +0800 Subject: [PATCH 6/6] fix: Update metadata file --- cli/artifacts/metadata.scale | Bin 152575 -> 153831 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/cli/artifacts/metadata.scale b/cli/artifacts/metadata.scale index 62c06839d5f2ac5b9a6be15ce0bd705ea73ac0b7..d67922f23d34ddc28423ad6569cff71ab0ff0f48 100644 GIT binary patch delta 8010 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 delta 7171 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 iCzOWb68uZcu}L*%R;c9_4yS8CX>d|9DwPf@