Skip to content
Snippets Groups Projects
Commit 6c9b611d authored by Éloïs's avatar Éloïs
Browse files

Merge branch...

Merge branch '303-create-a-runtime-api-universaldividendapi_account_balances-to-retrieve-total-and-transferable' into 'master'

Resolve "Create a runtime API UniversalDividendApi_account_balances to retrieve total and transferable account balances" (!328)

Closes #303

* update metadata

* add runtime API: UniversalDividendApi_account_total_balance
parent 587162e6
No related branches found
No related tags found
1 merge request!328Resolve "Create a runtime API UniversalDividendApi_account_balances to retrieve total and transferable account balances"
Pipeline #40928 passed
......@@ -7379,6 +7379,7 @@ dependencies = [
"parity-scale-codec",
"scale-info",
"serde",
"sp-api",
"sp-arithmetic",
"sp-core",
"sp-io",
......
......@@ -36,12 +36,12 @@ std = [
"pallet-timestamp/std",
"scale-info/std",
"serde/std",
"sp-api/std",
"sp-arithmetic/std",
"sp-core/std",
"sp-io/std",
"sp-runtime/std",
]
### DOC ###
[package.metadata.docs.rs]
default-features = false
......@@ -57,6 +57,7 @@ pallet-balances = { workspace = true }
pallet-timestamp = { workspace = true }
scale-info = { workspace = true, features = ["derive"] }
serde = { workspace = true, features = ["derive"] }
sp-api = { workspace = true }
sp-arithmetic = { workspace = true }
sp-core = { workspace = true }
sp-io = { workspace = true }
......
......@@ -30,6 +30,7 @@
mod benchmarking;
mod compute_claim_uds;
mod runtime_api;
mod types;
mod weights;
......@@ -42,13 +43,14 @@ mod tests;
use duniter_primitives::Idty;
pub use pallet::*;
pub use runtime_api::*;
pub use types::*;
pub use weights::WeightInfo;
use frame_support::traits::{
fungible::{self, Balanced, Mutate},
tokens::{Precision, Preservation},
OnTimestampSet,
fungible::{self, Balanced, Inspect, Mutate},
tokens::{Fortitude, Precision, Preservation},
OnTimestampSet, ReservableCurrency,
};
use sp_arithmetic::{
per_things::Perbill,
......@@ -83,7 +85,10 @@ pub mod pallet {
type MomentIntoBalance: Convert<Self::Moment, BalanceOf<Self>>;
/// The currency type used in this pallet.
type Currency: fungible::Balanced<Self::AccountId> + fungible::Mutate<Self::AccountId>;
type Currency: fungible::Balanced<Self::AccountId>
+ fungible::Mutate<Self::AccountId>
+ fungible::Inspect<Self::AccountId>
+ ReservableCurrency<Self::AccountId>;
/// Maximum number of past UD revaluations to keep in storage.
#[pallet::constant]
......@@ -482,6 +487,41 @@ pub mod pallet {
<T as pallet::Config>::WeightInfo::on_removed_member(0)
}
}
/// Get the total balance information for an account
///
/// Returns an object with three fields:
/// - `transferable`: sum of free + unclaim_uds
/// - `reserved`: reserved balance
/// - `unclaim_uds`: amount of unclaimed UDs computed by compute_claim_uds
pub fn account_balances(who: &T::AccountId) -> crate::AccountBalances<BalanceOf<T>> {
let total_balance = T::Currency::total_balance(who);
let reducible_balance =
T::Currency::reducible_balance(who, Preservation::Preserve, Fortitude::Polite);
// Calculate unclaimed UDs
let current_ud_index = CurrentUdIndex::<T>::get();
let maybe_first_eligible_ud = T::MembersStorage::get(who);
let unclaim_uds =
if let FirstEligibleUd(Some(ref first_ud_index)) = maybe_first_eligible_ud {
let past_reevals = PastReevals::<T>::get();
compute_claim_uds::compute_claim_uds(
current_ud_index,
first_ud_index.get(),
past_reevals.into_iter(),
)
.1
} else {
Zero::zero()
};
crate::AccountBalances {
total: total_balance.saturating_add(unclaim_uds),
transferable: reducible_balance.saturating_add(unclaim_uds),
unclaim_uds,
}
}
}
}
......
// Copyright 2021 Axiom-Team
//
// This file is part of Duniter-v2S.
//
// Duniter-v2S is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// Duniter-v2S is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
use codec::{Codec, Decode, Encode};
use scale_info::TypeInfo;
use sp_runtime::RuntimeDebug;
sp_api::decl_runtime_apis! {
/// Runtime API for Universal Dividend pallet
pub trait UniversalDividendApi<AccountId, Balance>
where
AccountId: Codec,
AccountBalances<Balance>: Codec,
{
/// Get the total balance information for an account
///
/// Returns an object with three fields:
/// - `total`: total balance
/// - `transferable`: sum of reducible + unclaim_uds
/// - `unclaim_uds`: amount of unclaimed UDs
fn account_balances(account: AccountId) -> AccountBalances<Balance>;
}
}
/// Account total balance information
#[derive(Encode, Decode, TypeInfo, Clone, PartialEq, RuntimeDebug)]
pub struct AccountBalances<Balance> {
/// The total amount of funds for which the user is the ultimate beneficial owner.
/// Includes funds that may not be transferable (e.g., reserved balance, existential deposit).
pub total: Balance,
/// The maximum amount of funds that can be successfully withdrawn or transferred
/// (includes unclaimed UDs).
pub transferable: Balance,
/// The total amount of unclaimed UDs (accounts for any re-evaluations of UDs).
pub unclaim_uds: Balance,
}
......@@ -15,7 +15,7 @@
// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
use crate::mock::*;
use frame_support::{assert_err, assert_ok, assert_storage_noop};
use frame_support::{assert_err, assert_ok, assert_storage_noop, traits::ReservableCurrency};
#[test]
fn test_claim_uds() {
......@@ -354,3 +354,51 @@ fn test_ud_creation() {
assert_eq!(UniversalDividend::total_money_created(), 25_671);
});
}
#[test]
fn test_account_balances() {
new_test_ext(UniversalDividendConfig {
first_reeval: Some(48_000),
first_ud: Some(12_000),
initial_monetary_mass: 0,
initial_members: vec![1, 2, 3],
ud: 1_000,
})
.execute_with(|| {
// Initially, all accounts have zero balance
let balance_info = UniversalDividend::account_balances(&1);
assert_eq!(balance_info.transferable, 0);
assert_eq!(balance_info.total, 0);
assert_eq!(balance_info.unclaim_uds, 0);
// Create some UDs and claim them
run_to_block(2);
assert_ok!(UniversalDividend::claim_uds(RuntimeOrigin::signed(1)));
// Check balance after claiming
let balance_info = UniversalDividend::account_balances(&1);
assert_eq!(balance_info.transferable, 1000 - 10); // free (1000) + unclaim_uds (0) - existantial deposit (10)
assert_eq!(balance_info.total, 1000); // transferable + reserved
assert_eq!(balance_info.unclaim_uds, 0);
// Create more UDs but don't claim them
run_to_block(4);
let balance_info = UniversalDividend::account_balances(&1);
assert_eq!(balance_info.transferable, 1000 + 1000 - 10); // free (1000) + unclaim_uds (1000) - existantial deposit (10)
assert_eq!(balance_info.total, 2000); // transferable + reserved
assert_eq!(balance_info.unclaim_uds, 1000);
// Test with reserved balance
assert_ok!(Balances::reserve(&1, 500));
let balance_info = UniversalDividend::account_balances(&1);
assert_eq!(balance_info.transferable, 500 + 1000 - 10); // free (500) + unclaim_uds (1000) - existantial deposit (10)
assert_eq!(balance_info.total, 2000); // transferable + reserved
assert_eq!(balance_info.unclaim_uds, 1000);
// Test non-member account
let balance_info = UniversalDividend::account_balances(&4);
assert_eq!(balance_info.transferable, 0);
assert_eq!(balance_info.total, 0);
assert_eq!(balance_info.unclaim_uds, 0);
});
}
No preview for this file type
......@@ -218,6 +218,13 @@ impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Ba
TransactionPayment::length_to_fee(length)
}
}
impl pallet_universal_dividend::UniversalDividendApi<Block, AccountId, Balance> for Runtime {
fn account_balances(account: AccountId) -> pallet_universal_dividend::AccountBalances<Balance> {
UniversalDividend::account_balances(&account)
}
}
impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
frame_support::genesis_builder_helper::build_state::<RuntimeGenesisConfig>(config)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment