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

Merge branch...

Merge branch '308-add-a-runtime-api-to-simulate-max-net-tx-cost-for-the-end-user-fees-refund' into 'master'

Add runtime api `DuniterAccountApi_estimate_cost`to estimate net tx cost for the end user (!331)

Closes #308

* update metadata

* renames

* Add runtime api DuniterAccountApi_estimate_fees_and_refund
parent 484daf48
No related branches found
No related tags found
1 merge request!331Add runtime api `DuniterAccountApi_estimate_cost`to estimate net tx cost for the end user
Pipeline #40986 passed
......@@ -2635,6 +2635,9 @@ dependencies = [
[[package]]
name = "duniter-primitives"
version = "1.0.0"
dependencies = [
"sp-runtime",
]
[[package]]
name = "dyn-clonable"
......@@ -6971,6 +6974,7 @@ dependencies = [
"parity-scale-codec",
"scale-info",
"serde",
"sp-api",
"sp-core",
"sp-io",
"sp-runtime",
......
......@@ -29,7 +29,6 @@ std = [
"sp-runtime/std",
]
try-runtime = [
"duniter-primitives/try-runtime",
"frame-support/try-runtime",
"frame-system/try-runtime",
"sp-runtime/try-runtime",
......
......@@ -35,12 +35,12 @@ std = [
"pallet-treasury/std",
"scale-info/std",
"serde/std",
"sp-api/std",
"sp-core/std",
"sp-io/std",
"sp-runtime/std",
]
try-runtime = [
"duniter-primitives/try-runtime",
"frame-support/try-runtime",
"frame-system/try-runtime",
"pallet-balances/try-runtime",
......@@ -68,6 +68,7 @@ scale-info = { workspace = true, features = ["derive"] }
frame-benchmarking = { workspace = true, optional = true }
frame-support = { workspace = true }
frame-system = { workspace = true }
sp-api = { workspace = true }
sp-core = { workspace = true }
sp-io = { workspace = true }
sp-runtime = { workspace = true }
......
......@@ -31,19 +31,23 @@
#![cfg_attr(not(feature = "std"), no_std)]
mod benchmarking;
pub mod weights;
mod benchmarking;
mod runtime_api;
mod types;
pub mod weights;
pub use pallet::*;
pub use runtime_api::*;
pub use types::*;
pub use weights::WeightInfo;
use core::cmp;
use duniter_primitives::GetSigner;
#[cfg(feature = "runtime-benchmarks")]
use frame_support::traits::tokens::fungible::Mutate;
use frame_support::{
dispatch::{DispatchInfo, GetDispatchInfo},
pallet_prelude::*,
traits::{
fungible,
......@@ -53,13 +57,15 @@ use frame_support::{
},
};
use frame_system::pallet_prelude::*;
use pallet_quota::traits::RefundFee;
use pallet_quota::RefundFee;
use pallet_transaction_payment::OnChargeTransaction;
use scale_info::prelude::{
collections::{BTreeMap, BTreeSet},
fmt::Debug,
};
use sp_runtime::traits::{DispatchInfoOf, PostDispatchInfoOf, Saturating};
use sp_runtime::traits::{
DispatchInfoOf, Dispatchable, ExtrinsicLike, PostDispatchInfoOf, Saturating,
};
#[allow(unreachable_patterns)]
#[frame_support::pallet]
......@@ -98,7 +104,7 @@ pub mod pallet {
type InnerOnChargeTransaction: OnChargeTransaction<Self>;
/// A type that implements the refund behavior for transaction fees.
type Refund: pallet_quota::traits::RefundFee<Self>;
type Refund: pallet_quota::RefundFee<Self>;
}
// GENESIS STUFF //
......@@ -187,6 +193,48 @@ pub mod pallet {
}
}
// PUBLIC FUNCTIONS //
impl<T: Config> Pallet<T> {
pub fn estimate_cost<Extrinsic>(
unchecked_extrinsic: Extrinsic,
) -> EstimatedCost<BalanceOf<T>>
where
BalanceOf<T>: PartialOrd,
Extrinsic: Encode + ExtrinsicLike + GetDispatchInfo + GetSigner<T::Lookup>,
T::RuntimeCall: Dispatchable<Info = DispatchInfo>,
<T as pallet_transaction_payment::Config>::OnChargeTransaction:
pallet_transaction_payment::OnChargeTransaction<T, Balance = BalanceOf<T>>,
{
let signer = unchecked_extrinsic.get_signer();
let len = unchecked_extrinsic.encoded_size();
let fees: BalanceOf<T> = pallet_transaction_payment::Pallet::<T>::query_info(
unchecked_extrinsic,
len as u32,
)
.partial_fee;
let refund: BalanceOf<T> = if let Some(signer) = signer {
let account_data = frame_system::Pallet::<T>::get(&signer);
if let Some(idty_index) = account_data.linked_idty {
pallet_quota::Pallet::<T>::estimate_quota_refund(idty_index)
} else {
Zero::zero()
}
} else {
Zero::zero()
};
EstimatedCost {
cost: if fees > refund {
fees - refund
} else {
Zero::zero()
},
fees,
refund,
}
}
}
// INTERNAL FUNCTIONS //
impl<T: Config> Pallet<T> {
/// Unlink the account from its associated identity.
......
// 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 duniter account pallet
pub trait DuniterAccountApi<Balance>
where
EstimatedCost<Balance>: Codec,
{
/// Simulate the maximum cost of an extrinsic
///
/// Returns an object with two fields:
/// - `max_cost`: estimated effective cost for the user (fees - refund)
/// - `max_fees`: estimated amount of fees for the extrinsic
/// - `min_refund`: estimated amount of refund from quota
fn estimate_cost(
uxt: Block::Extrinsic,
) -> EstimatedCost<Balance>;
}
}
/// Account total balance information
#[derive(Encode, Decode, TypeInfo, Clone, PartialEq, RuntimeDebug)]
pub struct EstimatedCost<Balance> {
/// The estimated effective cost for the user (fees - refund)
pub cost: Balance,
/// The estimated amount of fees for the extrinsic
pub fees: Balance,
/// The estimated amount of refund from quota
pub refund: Balance,
}
......@@ -31,7 +31,6 @@ std = [
"sp-state-machine/std",
]
try-runtime = [
"duniter-primitives/try-runtime",
"frame-support/try-runtime",
"frame-system/try-runtime",
"sp-runtime/try-runtime",
......
......@@ -37,8 +37,9 @@
#![cfg_attr(not(feature = "std"), no_std)]
pub mod traits;
pub mod weights;
mod benchmarking;
mod traits;
mod weights;
#[cfg(test)]
mod mock;
......@@ -46,17 +47,16 @@ mod mock;
#[cfg(test)]
mod tests;
pub mod benchmarking;
use crate::traits::*;
use frame_support::{
pallet_prelude::*,
traits::{Currency, ExistenceRequirement},
};
use frame_system::pallet_prelude::*;
pub use pallet::*;
use scale_info::prelude::vec::Vec;
use sp_runtime::traits::Zero;
pub use pallet::*;
pub use traits::*;
pub use weights::WeightInfo;
#[allow(unreachable_patterns)]
......@@ -162,6 +162,25 @@ pub mod pallet {
// from inside the quota pallet, we use events as mentioned in
// https://substrate.stackexchange.com/questions/9854/emitting-errors-from-hooks-like-on-initialize
// PUBLIC FUNCTIONS //
impl<T: Config> Pallet<T> {
/// Estimates the quota refund amount for an identity
/// The estimation simulate a refund request at the current block
pub fn estimate_quota_refund(idty_index: IdtyId<T>) -> BalanceOf<T> {
if is_eligible_for_refund::<T>(idty_index) {
if let Some(ref mut quota) = IdtyQuota::<T>::get(idty_index) {
Self::update_quota(quota);
quota.amount
} else {
Zero::zero()
}
} else {
Zero::zero()
}
}
}
// INTERNAL FUNCTIONS //
impl<T: Config> Pallet<T> {
/// Adds a new refund request to the refund queue.
......
......@@ -13,7 +13,11 @@ version.workspace = true
default-features = false
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
sp-runtime = { workspace = true }
[features]
default = ["std"]
std = []
try-runtime = []
std = [
"sp-runtime/std",
]
......@@ -27,6 +27,25 @@ pub fn validate_idty_name(idty_name: &[u8]) -> bool {
.all(|c| c.is_ascii_alphanumeric() || *c == b'-' || *c == b'_')
}
pub trait GetSigner<Lookup: sp_runtime::traits::StaticLookup> {
fn get_signer(&self) -> Option<Lookup::Target>;
}
impl<Address: Clone, Lookup, Call, Signature, Extension> GetSigner<Lookup>
for sp_runtime::generic::UncheckedExtrinsic<Address, Call, Signature, Extension>
where
Lookup: sp_runtime::traits::StaticLookup<Source = Address>,
{
fn get_signer(&self) -> Option<Lookup::Target> {
match &self.preamble {
sp_runtime::generic::Preamble::Signed(signer, _, _) => {
Lookup::lookup(signer.clone()).ok()
}
_ => None,
}
}
}
/// trait used to go from index to owner key and reverse
// replaces less explicit "Convert" implementations
pub trait Idty<IdtyIndex, AccountId> {
......
No preview for this file type
......@@ -71,7 +71,6 @@ std = [
"sp-weights/std",
]
try-runtime = [
"duniter-primitives/try-runtime",
"frame-support/try-runtime",
"frame-system/try-runtime",
"pallet-authority-members/try-runtime",
......
......@@ -219,6 +219,14 @@ impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Ba
}
}
impl pallet_duniter_account::DuniterAccountApi<Block, Balance> for Runtime {
fn estimate_cost(
uxt: <Block as BlockT>::Extrinsic,
) -> pallet_duniter_account::EstimatedCost<Balance> {
pallet_duniter_account::Pallet::<Runtime>::estimate_cost(uxt)
}
}
impl pallet_universal_dividend::UniversalDividendApi<Block, AccountId, Balance> for Runtime {
fn account_balances(account: AccountId) -> pallet_universal_dividend::AccountBalances<Balance> {
UniversalDividend::account_balances(&account)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment