From f4ad8bddc6f73cf7d98964ca18a0495f07bbdedd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Andr=C3=A9s=20Dorado=20Su=C3=A1rez?= Date: Thu, 12 Dec 2024 00:05:29 -0500 Subject: [PATCH 1/7] fix(fc-traits-gas-tank): make `GasFueler` refill using a tank ID --- traits/gas-tank/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/traits/gas-tank/src/lib.rs b/traits/gas-tank/src/lib.rs index ff7a574..0b2b8f1 100644 --- a/traits/gas-tank/src/lib.rs +++ b/traits/gas-tank/src/lib.rs @@ -29,11 +29,11 @@ pub trait GasBurner { /// Handles fueling _"gas"_ on a tank to spend in future transactions pub trait GasFueler { - type AccountId: Parameter; + type TankId: Parameter; type Gas: Parameter; /// Refills as much `gas` as possible returning what the updated amount of gas in the tank. /// /// This method is expected not to fail. - fn refuel_gas(who: &Self::AccountId, gas: &Self::Gas) -> Self::Gas; + fn refuel_gas(id: &Self::TankId, gas: &Self::Gas) -> Self::Gas; } From 06fe556930a5b94e852b08abe5d548484c910cf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Andr=C3=A9s=20Dorado=20Su=C3=A1rez?= Date: Thu, 12 Dec 2024 00:05:58 -0500 Subject: [PATCH 2/7] fix(fc-traits-gas-tank): create `MakeTank` trait --- traits/gas-tank/src/lib.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/traits/gas-tank/src/lib.rs b/traits/gas-tank/src/lib.rs index 0b2b8f1..eb792ac 100644 --- a/traits/gas-tank/src/lib.rs +++ b/traits/gas-tank/src/lib.rs @@ -1,6 +1,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use frame_support::Parameter; +use sp_runtime::traits::BlockNumber; #[cfg(test)] mod tests; @@ -37,3 +38,19 @@ pub trait GasFueler { /// This method is expected not to fail. fn refuel_gas(id: &Self::TankId, gas: &Self::Gas) -> Self::Gas; } + +pub trait MakeTank { + type TankId: Parameter; + type Gas: Parameter; + type BlockNumber: BlockNumber; + + /// Creates a new tank, allowing to specify a max gas `capacity` and a `periodicity` after + /// which the tank gets renewed. + /// + /// Returns `Some(())` if the creation was successful, or `None` otherwise. + fn make_tank( + id: &Self::TankId, + capacity: Option, + periodicity: Option, + ) -> Option<()>; +} From 556fd9fa4147fb6e4f7442723e4c82fe1ce754f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Andr=C3=A9s=20Dorado=20Su=C3=A1rez?= Date: Thu, 12 Dec 2024 00:06:30 -0500 Subject: [PATCH 3/7] fix(fc-traits-gas-tank): `gas_tank` shouldn't increase usage if the tank's capacity is unlimited --- traits/gas-tank/src/impl_nonfungibles.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/traits/gas-tank/src/impl_nonfungibles.rs b/traits/gas-tank/src/impl_nonfungibles.rs index 19b3dd3..7f2c476 100644 --- a/traits/gas-tank/src/impl_nonfungibles.rs +++ b/traits/gas-tank/src/impl_nonfungibles.rs @@ -98,7 +98,9 @@ where let mut gas_tank: MembershipWeightTank = F::typed_system_attribute(&collection, Some(&item), &ATTR_MEMBERSHIP_GAS)?; - gas_tank.used = gas_tank.used.checked_add(used)?; + if gas_tank.max_per_period.is_some() { + gas_tank.used = gas_tank.used.checked_add(used)?; + } F::set_typed_attribute(&collection, &item, &ATTR_MEMBERSHIP_GAS, &gas_tank).ok()?; let max_weight = gas_tank.max_per_period?; From 9d48e8e5fefc6fe086376357cb8fa93d77c2b6a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Andr=C3=A9s=20Dorado=20Su=C3=A1rez?= Date: Thu, 12 Dec 2024 00:07:03 -0500 Subject: [PATCH 4/7] feat(fc-traits-gas-tank): implement `GasFueler` and `MakeTank` for `NonFungibleGasBurner` --- traits/gas-tank/src/impl_nonfungibles.rs | 68 ++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/traits/gas-tank/src/impl_nonfungibles.rs b/traits/gas-tank/src/impl_nonfungibles.rs index 7f2c476..8d0476a 100644 --- a/traits/gas-tank/src/impl_nonfungibles.rs +++ b/traits/gas-tank/src/impl_nonfungibles.rs @@ -109,3 +109,71 @@ where .unwrap_or_default() } } + +impl GasFueler for NonFungibleGasBurner +where + T: frame_system::Config, + BlockNumberFor: Bounded, + F: nonfungibles_v2::Inspect + + nonfungibles_v2::InspectEnumerable + + nonfungibles_v2::Mutate, + ItemConfig: Default, + F::CollectionId: 'static, + F::ItemId: 'static, +{ + type TankId = (F::CollectionId, F::ItemId); + type Gas = Weight; + + fn refuel_gas((collection_id, item_id): &Self::TankId, gas: &Self::Gas) -> Self::Gas { + let Some(mut gas_tank): Option> = + F::typed_system_attribute(collection_id, Some(item_id), &ATTR_MEMBERSHIP_GAS) + else { + return Self::Gas::zero(); + }; + + gas_tank.used = gas_tank.used.saturating_sub(*gas); + + // Should infallibly save the tank, given that it already got a tank + let _ = F::set_typed_attribute(collection_id, item_id, &ATTR_MEMBERSHIP_GAS, &gas_tank); + + if gas_tank.max_per_period.is_some() { + Weight::MAX + } else { + gas_tank + .max_per_period + .unwrap_or_default() + .saturating_sub(gas_tank.used) + } + } +} + +impl MakeTank for NonFungibleGasBurner +where + T: frame_system::Config, + BlockNumberFor: Bounded, + F: nonfungibles_v2::Inspect + + nonfungibles_v2::InspectEnumerable + + nonfungibles_v2::Mutate, + ItemConfig: Default, + F::CollectionId: 'static, + F::ItemId: 'static, +{ + type TankId = (F::CollectionId, F::ItemId); + type Gas = Weight; + type BlockNumber = BlockNumberFor; + + fn make_tank( + (collection_id, item_id): &Self::TankId, + capacity: Option, + periodicity: Option, + ) -> Option<()> { + let tank = MembershipWeightTank:: { + since: frame_system::Pallet::::block_number(), + used: Weight::zero(), + period: periodicity, + max_per_period: capacity, + }; + + F::set_typed_attribute(&collection_id, item_id, &ATTR_MEMBERSHIP_GAS, &tank).ok() + } +} From 0e0a72d94413a66edd4b476b73ea0ac5169a0204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Andr=C3=A9s=20Dorado=20Su=C3=A1rez?= Date: Thu, 12 Dec 2024 00:35:17 -0500 Subject: [PATCH 5/7] feat(fc-traits-gas-tank): refactor `NonFungibleGasTank`. Improves readability and maintainability. --- traits/gas-tank/src/impl_nonfungibles.rs | 87 +++++++++++++++--------- traits/gas-tank/src/lib.rs | 2 +- traits/gas-tank/src/tests.rs | 16 ++--- 3 files changed, 63 insertions(+), 42 deletions(-) diff --git a/traits/gas-tank/src/impl_nonfungibles.rs b/traits/gas-tank/src/impl_nonfungibles.rs index 8d0476a..545c955 100644 --- a/traits/gas-tank/src/impl_nonfungibles.rs +++ b/traits/gas-tank/src/impl_nonfungibles.rs @@ -14,14 +14,42 @@ pub const ATTR_MEMBERSHIP_GAS: &[u8] = b"membership_gas"; pub const ATTR_GAS_TX_PAY_WITH_MEMBERSHIP: &[u8] = b"mbmshp_pays_gas"; #[derive(Encode, Decode, Debug)] -pub struct MembershipWeightTank { - pub since: BlockNumberFor, - pub used: Weight, - pub period: Option>, - pub max_per_period: Option, +pub struct WeightTank { + pub(crate) since: BlockNumberFor, + pub(crate) used: Weight, + pub(crate) period: Option>, + pub(crate) capacity_per_period: Option, } -impl Default for MembershipWeightTank +impl WeightTank +where + T: frame_system::Config, +{ + fn new(capacity_per_period: Option, period: Option>) -> Self { + Self { + since: frame_system::Pallet::::block_number(), + used: Weight::zero(), + period, + capacity_per_period, + } + } + + fn get(collection_id: &F::CollectionId, item_id: &F::ItemId) -> Option + where + F: nonfungibles_v2::Inspect, + { + F::typed_system_attribute(collection_id, Some(item_id), &ATTR_MEMBERSHIP_GAS) + } + + fn put(&self, collection_id: &F::CollectionId, item_id: &F::ItemId) -> Option<()> + where + F: nonfungibles_v2::Inspect + nonfungibles_v2::Mutate, + { + F::set_typed_attribute(collection_id, item_id, &ATTR_MEMBERSHIP_GAS, self).ok() + } +} + +impl Default for WeightTank where T: frame_system::Config, BlockNumberFor: Default, @@ -31,14 +59,14 @@ where since: Default::default(), used: Default::default(), period: Default::default(), - max_per_period: Default::default(), + capacity_per_period: Default::default(), } } } -pub struct NonFungibleGasBurner(PhantomData<(T, F, I)>); +pub struct NonFungibleGasTank(PhantomData<(T, F, I)>); -impl GasBurner for NonFungibleGasBurner +impl GasBurner for NonFungibleGasTank where T: frame_system::Config, BlockNumberFor: Bounded, @@ -52,21 +80,19 @@ where fn check_available_gas(who: &Self::AccountId, estimated: &Self::Gas) -> Option { F::owned(who).find_map(|(collection, item)| { - let mut gas_tank: MembershipWeightTank = - F::typed_system_attribute(&collection, Some(&item), &ATTR_MEMBERSHIP_GAS)?; + let mut gas_tank = WeightTank::::get::(&collection, &item)?; let block_number = frame_system::Pallet::::block_number(); let period = gas_tank.period.unwrap_or(BlockNumberFor::::max_value()); - let Some(max_weight) = gas_tank.max_per_period else { + let Some(max_weight) = gas_tank.capacity_per_period else { return Some(Weight::MAX); }; if block_number.checked_sub(&gas_tank.since)? > period { gas_tank.since = block_number.checked_add(&period)?; gas_tank.used = Weight::zero(); - - F::set_typed_attribute(&collection, &item, &ATTR_MEMBERSHIP_GAS, &gas_tank).ok()?; + gas_tank.put::(&collection, &item)?; }; let remaining = max_weight.checked_sub(&gas_tank.used.checked_add(estimated)?)?; @@ -95,22 +121,22 @@ where F::clear_typed_attribute(&collection, &item, &ATTR_GAS_TX_PAY_WITH_MEMBERSHIP) .ok()?; - let mut gas_tank: MembershipWeightTank = - F::typed_system_attribute(&collection, Some(&item), &ATTR_MEMBERSHIP_GAS)?; + let mut gas_tank = WeightTank::::get::(&collection, &item)?; - if gas_tank.max_per_period.is_some() { + if gas_tank.capacity_per_period.is_some() { gas_tank.used = gas_tank.used.checked_add(used)?; } - F::set_typed_attribute(&collection, &item, &ATTR_MEMBERSHIP_GAS, &gas_tank).ok()?; - let max_weight = gas_tank.max_per_period?; + gas_tank.put::(&collection, &item)?; + + let max_weight = gas_tank.capacity_per_period?; Some(max_weight.saturating_sub(gas_tank.used)) }) .unwrap_or_default() } } -impl GasFueler for NonFungibleGasBurner +impl GasFueler for NonFungibleGasTank where T: frame_system::Config, BlockNumberFor: Bounded, @@ -125,7 +151,7 @@ where type Gas = Weight; fn refuel_gas((collection_id, item_id): &Self::TankId, gas: &Self::Gas) -> Self::Gas { - let Some(mut gas_tank): Option> = + let Some(mut gas_tank): Option> = F::typed_system_attribute(collection_id, Some(item_id), &ATTR_MEMBERSHIP_GAS) else { return Self::Gas::zero(); @@ -134,20 +160,22 @@ where gas_tank.used = gas_tank.used.saturating_sub(*gas); // Should infallibly save the tank, given that it already got a tank - let _ = F::set_typed_attribute(collection_id, item_id, &ATTR_MEMBERSHIP_GAS, &gas_tank); + gas_tank + .put::(collection_id, item_id) + .unwrap_or_default(); - if gas_tank.max_per_period.is_some() { + if gas_tank.capacity_per_period.is_some() { Weight::MAX } else { gas_tank - .max_per_period + .capacity_per_period .unwrap_or_default() .saturating_sub(gas_tank.used) } } } -impl MakeTank for NonFungibleGasBurner +impl MakeTank for NonFungibleGasTank where T: frame_system::Config, BlockNumberFor: Bounded, @@ -167,13 +195,6 @@ where capacity: Option, periodicity: Option, ) -> Option<()> { - let tank = MembershipWeightTank:: { - since: frame_system::Pallet::::block_number(), - used: Weight::zero(), - period: periodicity, - max_per_period: capacity, - }; - - F::set_typed_attribute(&collection_id, item_id, &ATTR_MEMBERSHIP_GAS, &tank).ok() + WeightTank::::new(capacity, periodicity).put::(collection_id, item_id) } } diff --git a/traits/gas-tank/src/lib.rs b/traits/gas-tank/src/lib.rs index eb792ac..1c82307 100644 --- a/traits/gas-tank/src/lib.rs +++ b/traits/gas-tank/src/lib.rs @@ -10,7 +10,7 @@ mod impl_nonfungibles; pub trait GasTank: GasBurner + GasFueler {} -pub use impl_nonfungibles::NonFungibleGasBurner; +pub use impl_nonfungibles::NonFungibleGasTank; /// Handles burning _"gas"_ from a tank to be spendable in transactions pub trait GasBurner { diff --git a/traits/gas-tank/src/tests.rs b/traits/gas-tank/src/tests.rs index 6881790..54db47c 100644 --- a/traits/gas-tank/src/tests.rs +++ b/traits/gas-tank/src/tests.rs @@ -6,7 +6,7 @@ use frame_support::{ weights::Weight, }; use frame_system::EnsureNever; -use impl_nonfungibles::{MembershipWeightTank, NonFungibleGasBurner, ATTR_MEMBERSHIP_GAS}; +use impl_nonfungibles::{NonFungibleGasTank, WeightTank, ATTR_MEMBERSHIP_GAS}; use sp_runtime::{ traits::{IdentifyAccount, IdentityLookup, Verify}, MultiSignature, @@ -89,7 +89,7 @@ impl pallet_nfts::Config for Test { type Helper = (); } -pub type MembershipsGas = NonFungibleGasBurner; +pub type MembershipsGas = NonFungibleGasTank; parameter_types! { const CollectionOwner: AccountId = AccountId::new([0u8;32]); @@ -120,24 +120,24 @@ pub(crate) fn new_test_ext() -> sp_io::TestExternalities { ( 1, SmallMember::get(), - MembershipWeightTank:: { - max_per_period: Some(SmallTank::get()), + WeightTank:: { + capacity_per_period: Some(SmallTank::get()), ..Default::default() }, ), ( 2, MediumMember::get(), - MembershipWeightTank:: { - max_per_period: Some(MediumTank::get()), + WeightTank:: { + capacity_per_period: Some(MediumTank::get()), ..Default::default() }, ), ( 3, LargeMember::get(), - MembershipWeightTank:: { - max_per_period: Some(LargeTank::get()), + WeightTank:: { + capacity_per_period: Some(LargeTank::get()), ..Default::default() }, ), From 117d43c38d62a099f69745c7b1bd9139a91daaee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Andr=C3=A9s=20Dorado=20Su=C3=A1rez?= Date: Thu, 12 Dec 2024 01:09:31 -0500 Subject: [PATCH 6/7] feat(fc-traits-gas-tank): add additiona tests to assert `GasFueler` and `MakeTank` --- traits/gas-tank/src/impl_nonfungibles.rs | 22 +++---- traits/gas-tank/src/tests.rs | 83 ++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 11 deletions(-) diff --git a/traits/gas-tank/src/impl_nonfungibles.rs b/traits/gas-tank/src/impl_nonfungibles.rs index 545c955..478e861 100644 --- a/traits/gas-tank/src/impl_nonfungibles.rs +++ b/traits/gas-tank/src/impl_nonfungibles.rs @@ -34,7 +34,7 @@ where } } - fn get(collection_id: &F::CollectionId, item_id: &F::ItemId) -> Option + pub(crate) fn get(collection_id: &F::CollectionId, item_id: &F::ItemId) -> Option where F: nonfungibles_v2::Inspect, { @@ -85,7 +85,7 @@ where let block_number = frame_system::Pallet::::block_number(); let period = gas_tank.period.unwrap_or(BlockNumberFor::::max_value()); - let Some(max_weight) = gas_tank.capacity_per_period else { + let Some(capacity) = gas_tank.capacity_per_period else { return Some(Weight::MAX); }; @@ -95,7 +95,7 @@ where gas_tank.put::(&collection, &item)?; }; - let remaining = max_weight.checked_sub(&gas_tank.used.checked_add(estimated)?)?; + let remaining = capacity.checked_sub(&gas_tank.used.checked_add(estimated)?)?; F::set_typed_attribute( &collection, &item, @@ -157,6 +157,10 @@ where return Self::Gas::zero(); }; + if gas_tank.capacity_per_period.is_none() { + return Self::Gas::MAX; + } + gas_tank.used = gas_tank.used.saturating_sub(*gas); // Should infallibly save the tank, given that it already got a tank @@ -164,14 +168,10 @@ where .put::(collection_id, item_id) .unwrap_or_default(); - if gas_tank.capacity_per_period.is_some() { - Weight::MAX - } else { - gas_tank - .capacity_per_period - .unwrap_or_default() - .saturating_sub(gas_tank.used) - } + gas_tank + .capacity_per_period + .unwrap_or_default() + .saturating_sub(gas_tank.used) } } diff --git a/traits/gas-tank/src/tests.rs b/traits/gas-tank/src/tests.rs index 54db47c..7770f8b 100644 --- a/traits/gas-tank/src/tests.rs +++ b/traits/gas-tank/src/tests.rs @@ -97,10 +97,12 @@ parameter_types! { const SmallMember: AccountId = AccountId::new([1u8;32]); const MediumMember: AccountId = AccountId::new([2u8;32]); const LargeMember: AccountId = AccountId::new([3u8;32]); + const ExtraLargeMember: AccountId = AccountId::new([4u8;32]); SmallTank: Weight = <() as frame_system::WeightInfo>::remark(100); MediumTank: Weight = <() as frame_system::WeightInfo>::remark(1000); LargeTank: Weight = <() as frame_system::WeightInfo>::remark(10000); + ExtraLargeTank: Weight = <() as frame_system::WeightInfo>::remark(100000); } pub(crate) fn new_test_ext() -> sp_io::TestExternalities { @@ -239,3 +241,84 @@ mod gas_burner { }); } } + +mod gas_fueler { + use super::*; + + #[test] + fn it_works() { + new_test_ext().execute_with(|| { + // Burn gas on large tank + let remaining = MembershipsGas::check_available_gas( + &LargeMember::get(), + &<() as frame_system::WeightInfo>::remark(1000), + ) + .expect("gas to burn equals tank capacity; qed"); + + assert_eq!( + MembershipsGas::burn_gas( + &LargeMember::get(), + &remaining, + &<() as frame_system::WeightInfo>::remark(5000) + ), + LargeTank::get().saturating_sub(<() as frame_system::WeightInfo>::remark(5000)) + ); + + // Refuels gas + assert_eq!( + MembershipsGas::refuel_gas( + &(1, 3), + &<() as frame_system::WeightInfo>::remark(5000) + ), + LargeTank::get() + ); + }) + } +} + +mod make_tank { + use super::*; + + #[test] + fn it_works() { + use frame_support::traits::nonfungibles_v2::Mutate; + + new_test_ext().execute_with(|| { + assert_ok!(Memberships::mint_into( + &1, + &4, + &ExtraLargeMember::get(), + &Default::default(), + true, + )); + + MembershipsGas::make_tank(&(1, 4), Some(ExtraLargeTank::get()), None) + .expect("failed to register the tank"); + + // Burn gas on large tank + let remaining = MembershipsGas::check_available_gas( + &ExtraLargeMember::get(), + &ExtraLargeTank::get(), + ) + .expect("gas to burn equals tank capacity; qed"); + + assert_eq!( + MembershipsGas::burn_gas( + &ExtraLargeMember::get(), + &remaining, + &ExtraLargeTank::get(), + ), + Weight::zero() + ); + + // Refuels gas + assert_eq!( + MembershipsGas::refuel_gas( + &(1, 4), + &<() as frame_system::WeightInfo>::remark(100000) + ), + ExtraLargeTank::get() + ); + }) + } +} From 02f75e80682ba950d64152b2e59556757954613b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Andr=C3=A9s=20Dorado=20Su=C3=A1rez?= Date: Thu, 12 Dec 2024 01:43:49 -0500 Subject: [PATCH 7/7] chore(fc-traits-gas-tank): final refactoring --- traits/gas-tank/src/impl_nonfungibles.rs | 44 +++++++++++------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/traits/gas-tank/src/impl_nonfungibles.rs b/traits/gas-tank/src/impl_nonfungibles.rs index 478e861..3b7300c 100644 --- a/traits/gas-tank/src/impl_nonfungibles.rs +++ b/traits/gas-tank/src/impl_nonfungibles.rs @@ -80,22 +80,22 @@ where fn check_available_gas(who: &Self::AccountId, estimated: &Self::Gas) -> Option { F::owned(who).find_map(|(collection, item)| { - let mut gas_tank = WeightTank::::get::(&collection, &item)?; + let mut tank = WeightTank::::get::(&collection, &item)?; let block_number = frame_system::Pallet::::block_number(); - let period = gas_tank.period.unwrap_or(BlockNumberFor::::max_value()); + let period = tank.period.unwrap_or(BlockNumberFor::::max_value()); - let Some(capacity) = gas_tank.capacity_per_period else { + let Some(capacity) = tank.capacity_per_period else { return Some(Weight::MAX); }; - if block_number.checked_sub(&gas_tank.since)? > period { - gas_tank.since = block_number.checked_add(&period)?; - gas_tank.used = Weight::zero(); - gas_tank.put::(&collection, &item)?; + if block_number.checked_sub(&tank.since)? > period { + tank.since = block_number.checked_add(&period)?; + tank.used = Weight::zero(); + tank.put::(&collection, &item)?; }; - let remaining = capacity.checked_sub(&gas_tank.used.checked_add(estimated)?)?; + let remaining = capacity.checked_sub(&tank.used.checked_add(estimated)?)?; F::set_typed_attribute( &collection, &item, @@ -121,16 +121,16 @@ where F::clear_typed_attribute(&collection, &item, &ATTR_GAS_TX_PAY_WITH_MEMBERSHIP) .ok()?; - let mut gas_tank = WeightTank::::get::(&collection, &item)?; + let mut tank = WeightTank::::get::(&collection, &item)?; - if gas_tank.capacity_per_period.is_some() { - gas_tank.used = gas_tank.used.checked_add(used)?; + if tank.capacity_per_period.is_some() { + tank.used = tank.used.checked_add(used)?; } - gas_tank.put::(&collection, &item)?; + tank.put::(&collection, &item)?; - let max_weight = gas_tank.capacity_per_period?; - Some(max_weight.saturating_sub(gas_tank.used)) + let max_weight = tank.capacity_per_period?; + Some(max_weight.saturating_sub(tank.used)) }) .unwrap_or_default() } @@ -151,27 +151,23 @@ where type Gas = Weight; fn refuel_gas((collection_id, item_id): &Self::TankId, gas: &Self::Gas) -> Self::Gas { - let Some(mut gas_tank): Option> = - F::typed_system_attribute(collection_id, Some(item_id), &ATTR_MEMBERSHIP_GAS) - else { + let Some(mut tank) = WeightTank::::get::(collection_id, item_id) else { return Self::Gas::zero(); }; - if gas_tank.capacity_per_period.is_none() { + if tank.capacity_per_period.is_none() { return Self::Gas::MAX; } - gas_tank.used = gas_tank.used.saturating_sub(*gas); + tank.used = tank.used.saturating_sub(*gas); // Should infallibly save the tank, given that it already got a tank - gas_tank - .put::(collection_id, item_id) + tank.put::(collection_id, item_id) .unwrap_or_default(); - gas_tank - .capacity_per_period + tank.capacity_per_period .unwrap_or_default() - .saturating_sub(gas_tank.used) + .saturating_sub(tank.used) } }