From 6d4f4bfb7d527f22eaf7cb10605715cab7f567b0 Mon Sep 17 00:00:00 2001 From: librelois <c@elo.tf> Date: Thu, 19 May 2022 18:37:33 +0200 Subject: [PATCH] PoC about oneshot accounts --- pallets/duniter-account/src/lib.rs | 116 ++++++++++++++++++++++++++- pallets/duniter-account/src/types.rs | 10 ++- 2 files changed, 123 insertions(+), 3 deletions(-) diff --git a/pallets/duniter-account/src/lib.rs b/pallets/duniter-account/src/lib.rs index 0615fbd99..9cf1cf363 100644 --- a/pallets/duniter-account/src/lib.rs +++ b/pallets/duniter-account/src/lib.rs @@ -26,7 +26,7 @@ use frame_support::traits::{OnUnbalanced, StoredMap}; use frame_system::pallet_prelude::*; use pallet_provide_randomness::RequestId; use sp_core::H256; -use sp_runtime::traits::{Convert, Saturating, Zero}; +use sp_runtime::traits::{Convert, Saturating, StaticLookup, Zero}; #[frame_support::pallet] pub mod pallet { @@ -60,6 +60,11 @@ pub mod pallet { // STORAGE // + #[pallet::storage] + #[pallet::getter(fn oneshot_account)] + pub type OneshotAccounts<T: Config> = + StorageMap<_, Blake2_128Concat, T::AccountId, T::Balance, OptionQuery>; + #[pallet::storage] #[pallet::getter(fn pending_random_id_assignments)] pub type PendingRandomIdAssignments<T: Config> = @@ -133,14 +138,40 @@ pub mod pallet { /// the account creation price. /// [who, balance] ForceDestroy { + balance: T::Balance, who: T::AccountId, + }, + OneshotAccountCreated { + account: T::AccountId, balance: T::Balance, + creator: T::AccountId, + }, + OneshotAccountConsumed { + account: T::AccountId, + balance: T::Balance, + dest: T::AccountId, }, /// Random id assigned /// [account_id, random_id] RandomIdAssigned { who: T::AccountId, random_id: H256 }, } + // ERRORS // + + #[pallet::error] + pub enum Error<T> { + /// DestAccountNotExist + DestAccountNotExist, + /// ExistentialDeposit + ExistentialDeposit, + /// InsufficientBalance + InsufficientBalance, + /// OneshotAccouncAlreadyCreated + OneshotAccountAlreadyCreated, + /// OneshotAccountNotExist + OneshotAccountNotExist, + } + // HOOKS // #[pallet::hooks] impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> { @@ -217,6 +248,89 @@ pub mod pallet { total_weight } } + + // CALLS // + #[pallet::call] + impl<T: Config> Pallet<T> { + #[pallet::weight(500_000_000)] + pub fn create_oneshot_account( + origin: OriginFor<T>, + dest: <T::Lookup as StaticLookup>::Source, + #[pallet::compact] value: T::Balance, + ) -> DispatchResult { + let transactor = ensure_signed(origin)?; + let dest = T::Lookup::lookup(dest)?; + + ensure!( + value >= T::ExistentialDeposit::get(), + Error::<T>::ExistentialDeposit + ); + ensure!( + OneshotAccounts::<T>::get(&dest).is_none(), + Error::<T>::OneshotAccountAlreadyCreated + ); + + let transactor_data = frame_system::Account::<T>::get(&transactor).data; + let transactor_free_and_reserved = transactor_data + .free + .saturating_add(transactor_data.reserved); + let sufficient_balance = value.saturating_add(T::ExistentialDeposit::get()); + ensure!( + transactor_data.free >= value && transactor_free_and_reserved >= sufficient_balance, + Error::<T>::InsufficientBalance + ); + + frame_system::Account::<T>::mutate(&transactor, |a| a.data.sub_free(value)); + OneshotAccounts::<T>::insert(&dest, value); + Self::deposit_event(Event::OneshotAccountCreated { + account: dest, + balance: value, + creator: transactor, + }); + + Ok(()) + } + #[pallet::weight(500_000_000)] + pub fn consume_oneshot_account( + origin: OriginFor<T>, + dest: (bool, <T::Lookup as StaticLookup>::Source), + ) -> DispatchResult { + let transactor = ensure_signed(origin)?; + let dest_is_oneshot = dest.0; + let dest = T::Lookup::lookup(dest.1)?; + + let value = OneshotAccounts::<T>::take(&transactor) + .ok_or(Error::<T>::OneshotAccountNotExist)?; + + if dest_is_oneshot { + ensure!( + OneshotAccounts::<T>::get(&dest).is_none(), + Error::<T>::OneshotAccountAlreadyCreated + ); + OneshotAccounts::<T>::insert(&dest, value); + Self::deposit_event(Event::OneshotAccountConsumed { + account: transactor.clone(), + balance: value, + dest: dest.clone(), + }); + Self::deposit_event(Event::OneshotAccountCreated { + account: dest, + balance: value, + creator: transactor, + }); + } else { + let dest_data = frame_system::Account::<T>::get(&dest).data; + ensure!(dest_data.was_providing(), Error::<T>::DestAccountNotExist); + Self::deposit_event(Event::OneshotAccountConsumed { + account: transactor, + balance: value, + dest, + }); + } + + Ok(()) + } + } } impl<T> pallet_provide_randomness::OnFilledRandomness for Pallet<T> diff --git a/pallets/duniter-account/src/types.rs b/pallets/duniter-account/src/types.rs index 25135c3f6..8f1a6b16b 100644 --- a/pallets/duniter-account/src/types.rs +++ b/pallets/duniter-account/src/types.rs @@ -18,7 +18,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::pallet_prelude::*; use scale_info::TypeInfo; use sp_core::H256; -use sp_runtime::traits::Zero; +use sp_runtime::traits::{Saturating, Zero}; #[derive(Clone, Decode, Default, Encode, Eq, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)] pub struct AccountData<Balance> { @@ -28,12 +28,18 @@ pub struct AccountData<Balance> { fee_frozen: Balance, } -impl<Balance: Zero> AccountData<Balance> { +impl<Balance: Copy + Saturating + Zero> AccountData<Balance> { + pub fn free_and_reserved(&self) -> Balance { + self.free.saturating_add(self.reserved) + } pub fn set_balances(&mut self, new_balances: pallet_balances::AccountData<Balance>) { self.free = new_balances.free; self.reserved = new_balances.reserved; self.fee_frozen = new_balances.fee_frozen; } + pub fn sub_free(&mut self, amount: Balance) { + self.free = self.free.saturating_sub(amount); + } pub fn was_providing(&self) -> bool { !self.free.is_zero() || !self.reserved.is_zero() } -- GitLab