Skip to content

Commit 2604913

Browse files
committed
Default implementation of FungibleAdapter in a separate pallet
1 parent 6d22016 commit 2604913

File tree

6 files changed

+204
-20
lines changed

6 files changed

+204
-20
lines changed

Cargo.lock

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ subtensor-custom-rpc-runtime-api = { default-features = false, path = "pallets/s
6262
subtensor-precompiles = { default-features = false, path = "precompiles" }
6363
subtensor-runtime-common = { default-features = false, path = "common" }
6464
subtensor-swap-interface = { default-features = false, path = "pallets/swap-interface" }
65+
subtensor-transaction-fee = { default-features = false, path = "pallets/transaction-fee" }
6566

6667
async-trait = "0.1"
6768
cargo-husky = { version = "1", default-features = false }

pallets/transaction-fee/Cargo.toml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
[package]
2+
name = "subtensor-transaction-fee"
3+
version = "0.1.0"
4+
edition.workspace = true
5+
6+
[dependencies]
7+
codec = { workspace = true }
8+
frame-support = { workspace = true }
9+
frame-system = { workspace = true }
10+
log = { workspace = true }
11+
pallet-subtensor = { workspace = true }
12+
pallet-transaction-payment = { workspace = true }
13+
scale-info = { workspace = true }
14+
smallvec = { workspace = true }
15+
sp-runtime = { workspace = true }
16+
substrate-fixed = { workspace = true }
17+
subtensor-runtime-common = { workspace = true }
18+
19+
[lints]
20+
workspace = true
21+
22+
[features]
23+
default = ["std"]
24+
std = [
25+
"codec/std",
26+
"frame-support/std",
27+
"frame-system/std",
28+
"log/std",
29+
"pallet-subtensor/std",
30+
"pallet-transaction-payment/std",
31+
"scale-info/std",
32+
"sp-runtime/std",
33+
"substrate-fixed/std",
34+
"subtensor-runtime-common/std",
35+
]
36+
runtime-benchmarks = [
37+
"frame-support/runtime-benchmarks",
38+
"frame-system/runtime-benchmarks",
39+
"sp-runtime/runtime-benchmarks",
40+
]

pallets/transaction-fee/src/lib.rs

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
#![cfg_attr(not(feature = "std"), no_std)]
2+
3+
use frame_support::pallet_prelude::*;
4+
use frame_support::{
5+
traits::{
6+
Imbalance, OnUnbalanced,
7+
fungible::{Balanced, Credit, Debt, Inspect},
8+
tokens::{Precision, WithdrawConsequence},
9+
},
10+
weights::{WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial},
11+
};
12+
13+
use sp_runtime::{
14+
Perbill, Saturating,
15+
traits::{DispatchInfoOf, PostDispatchInfoOf},
16+
};
17+
// use substrate_fixed::types::U96F32;
18+
// use subtensor_runtime_common::{AlphaCurrency, NetUid};
19+
use pallet_transaction_payment::Config as PTPConfig;
20+
21+
use smallvec::smallvec;
22+
use subtensor_runtime_common::Balance;
23+
24+
pub use pallet_transaction_payment::OnChargeTransaction;
25+
26+
pub struct LinearWeightToFee;
27+
28+
impl WeightToFeePolynomial for LinearWeightToFee {
29+
type Balance = Balance;
30+
31+
fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
32+
let coefficient = WeightToFeeCoefficient {
33+
coeff_integer: 0,
34+
coeff_frac: Perbill::from_parts(500_000), // 0.5 unit per weight
35+
negative: false,
36+
degree: 1,
37+
};
38+
39+
smallvec![coefficient]
40+
}
41+
}
42+
43+
/// Custom FungibleAdapter based on standard FungibleAdapter from transsaction_payment
44+
/// FRAME pallet
45+
///
46+
pub struct FungibleAdapter<F, OU>(PhantomData<(F, OU)>);
47+
48+
impl<T, F, OU> OnChargeTransaction<T> for FungibleAdapter<F, OU>
49+
where
50+
T: PTPConfig,
51+
F: Balanced<T::AccountId>,
52+
OU: OnUnbalanced<Credit<T::AccountId, F>>,
53+
{
54+
type LiquidityInfo = Option<Credit<T::AccountId, F>>;
55+
type Balance = <F as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
56+
57+
fn withdraw_fee(
58+
who: &<T>::AccountId,
59+
call: &<T>::RuntimeCall,
60+
_dispatch_info: &DispatchInfoOf<<T>::RuntimeCall>,
61+
fee: Self::Balance,
62+
_tip: Self::Balance,
63+
) -> Result<Self::LiquidityInfo, TransactionValidityError> {
64+
log::error!("====================== withdraw_fee. Call = {:?}", call);
65+
66+
if fee.is_zero() {
67+
return Ok(None);
68+
}
69+
70+
match F::withdraw(
71+
who,
72+
fee,
73+
Precision::Exact,
74+
frame_support::traits::tokens::Preservation::Preserve,
75+
frame_support::traits::tokens::Fortitude::Polite,
76+
) {
77+
Ok(imbalance) => Ok(Some(imbalance)),
78+
Err(_) => Err(InvalidTransaction::Payment.into()),
79+
}
80+
}
81+
82+
fn can_withdraw_fee(
83+
who: &T::AccountId,
84+
_call: &T::RuntimeCall,
85+
_dispatch_info: &DispatchInfoOf<T::RuntimeCall>,
86+
fee: Self::Balance,
87+
_tip: Self::Balance,
88+
) -> Result<(), TransactionValidityError> {
89+
if fee.is_zero() {
90+
return Ok(());
91+
}
92+
93+
match F::can_withdraw(who, fee) {
94+
WithdrawConsequence::Success => Ok(()),
95+
_ => Err(InvalidTransaction::Payment.into()),
96+
}
97+
}
98+
99+
fn correct_and_deposit_fee(
100+
who: &<T>::AccountId,
101+
_dispatch_info: &DispatchInfoOf<<T>::RuntimeCall>,
102+
_post_info: &PostDispatchInfoOf<<T>::RuntimeCall>,
103+
corrected_fee: Self::Balance,
104+
tip: Self::Balance,
105+
already_withdrawn: Self::LiquidityInfo,
106+
) -> Result<(), TransactionValidityError> {
107+
if let Some(paid) = already_withdrawn {
108+
// Calculate how much refund we should return
109+
let refund_amount = paid.peek().saturating_sub(corrected_fee);
110+
// refund to the the account that paid the fees if it exists. otherwise, don't refind
111+
// anything.
112+
let refund_imbalance = if F::total_balance(who) > F::Balance::zero() {
113+
F::deposit(who, refund_amount, Precision::BestEffort)
114+
.unwrap_or_else(|_| Debt::<T::AccountId, F>::zero())
115+
} else {
116+
Debt::<T::AccountId, F>::zero()
117+
};
118+
// merge the imbalance caused by paying the fees and refunding parts of it again.
119+
let adjusted_paid: Credit<T::AccountId, F> = paid
120+
.offset(refund_imbalance)
121+
.same()
122+
.map_err(|_| TransactionValidityError::Invalid(InvalidTransaction::Payment))?;
123+
// Call someone else to handle the imbalance (fee and tip separately)
124+
let (tip, fee) = adjusted_paid.split(tip);
125+
OU::on_unbalanceds(Some(fee).into_iter().chain(Some(tip)));
126+
}
127+
128+
Ok(())
129+
}
130+
131+
#[cfg(feature = "runtime-benchmarks")]
132+
fn endow_account(who: &T::AccountId, amount: Self::Balance) {
133+
let _ = F::deposit(who, amount, Precision::BestEffort);
134+
}
135+
136+
#[cfg(feature = "runtime-benchmarks")]
137+
fn minimum_balance() -> Self::Balance {
138+
F::minimum_balance()
139+
}
140+
}

runtime/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pallet-subtensor-swap = { workspace = true }
3636
pallet-subtensor-swap-runtime-api = { workspace = true }
3737
substrate-fixed = { workspace = true }
3838
subtensor-swap-interface = { workspace = true }
39+
subtensor-transaction-fee = { workspace = true }
3940
frame-support = { workspace = true }
4041
pallet-grandpa = { workspace = true }
4142
pallet-insecure-randomness-collective-flip = { workspace = true }

runtime/src/lib.rs

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ use pallet_subtensor::rpc_info::{
4545
stake_info::StakeInfo,
4646
subnet_info::{SubnetHyperparams, SubnetHyperparamsV2, SubnetInfo, SubnetInfov2},
4747
};
48-
use smallvec::smallvec;
4948
use sp_api::impl_runtime_apis;
5049
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
5150
use sp_core::{
@@ -88,7 +87,9 @@ pub use frame_support::{
8887
pub use frame_system::Call as SystemCall;
8988
pub use pallet_balances::Call as BalancesCall;
9089
pub use pallet_timestamp::Call as TimestampCall;
91-
use pallet_transaction_payment::{ConstFeeMultiplier, FungibleAdapter, Multiplier};
90+
use pallet_transaction_payment::{ConstFeeMultiplier, Multiplier};
91+
use subtensor_transaction_fee::FungibleAdapter;
92+
9293
#[cfg(any(feature = "std", test))]
9394
pub use sp_runtime::BuildStorage;
9495
pub use sp_runtime::{Perbill, Permill};
@@ -445,23 +446,6 @@ impl pallet_balances::Config for Runtime {
445446
type DoneSlashHandler = ();
446447
}
447448

448-
pub struct LinearWeightToFee;
449-
450-
impl WeightToFeePolynomial for LinearWeightToFee {
451-
type Balance = Balance;
452-
453-
fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
454-
let coefficient = WeightToFeeCoefficient {
455-
coeff_integer: 0,
456-
coeff_frac: Perbill::from_parts(500_000),
457-
negative: false,
458-
degree: 1,
459-
};
460-
461-
smallvec!(coefficient)
462-
}
463-
}
464-
465449
parameter_types! {
466450
pub const OperationalFeeMultiplier: u8 = 5;
467451
pub FeeMultiplier: Multiplier = Multiplier::one();
@@ -496,7 +480,7 @@ impl pallet_transaction_payment::Config for Runtime {
496480
type RuntimeEvent = RuntimeEvent;
497481
type OnChargeTransaction = FungibleAdapter<Balances, TransactionFeeHandler>;
498482
// Convert dispatch weight to a chargeable fee.
499-
type WeightToFee = LinearWeightToFee;
483+
type WeightToFee = subtensor_transaction_fee::LinearWeightToFee;
500484
type OperationalFeeMultiplier = OperationalFeeMultiplier;
501485
type LengthToFee = IdentityFee<Balance>;
502486
type FeeMultiplierUpdate = ConstFeeMultiplier<FeeMultiplier>;

0 commit comments

Comments
 (0)