Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions pallets/transaction-fee/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ frame-system.workspace = true
log.workspace = true
pallet-balances = { workspace = true, default-features = false }
pallet-alpha-assets = { workspace = true, default-features = false }
pallet-evm.workspace = true
pallet-subtensor.workspace = true
pallet-subtensor-swap.workspace = true
pallet-transaction-payment.workspace = true
smallvec.workspace = true
sp-core.workspace = true
sp-runtime.workspace = true
sp-std.workspace = true
substrate-fixed.workspace = true
Expand Down Expand Up @@ -52,6 +54,7 @@ std = [
"pallet-balances/std",
"pallet-crowdloan/std",
"pallet-drand/std",
"pallet-evm/std",
"pallet-evm-chain-id/std",
"pallet-grandpa/std",
"pallet-preimage/std",
Expand All @@ -60,6 +63,7 @@ std = [
"pallet-subtensor-swap/std",
"pallet-transaction-payment/std",
"scale-info/std",
"sp-core/std",
"sp-runtime/std",
"sp-std/std",
"sp-consensus-aura/std",
Expand All @@ -80,6 +84,7 @@ runtime-benchmarks = [
"pallet-balances/runtime-benchmarks",
"pallet-crowdloan/runtime-benchmarks",
"pallet-drand/runtime-benchmarks",
"pallet-evm/runtime-benchmarks",
"pallet-grandpa/runtime-benchmarks",
"pallet-preimage/runtime-benchmarks",
"pallet-scheduler/runtime-benchmarks",
Expand Down
81 changes: 81 additions & 0 deletions pallets/transaction-fee/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ use frame_support::{
},
weights::{WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial},
};
use pallet_evm::{
AddressMapping, BalanceConverter, Config as EvmConfig, EvmBalance, OnChargeEVMTransaction,
};

// Runtime
use sp_runtime::{
Expand All @@ -29,6 +32,7 @@ use subtensor_swap_interface::SwapHandler;
// Misc
use core::marker::PhantomData;
use smallvec::smallvec;
use sp_core::H160;
use sp_runtime::traits::SaturatedConversion;
use sp_std::vec::Vec;
use subtensor_runtime_common::{AlphaBalance, AuthorshipInfo, NetUid, TaoBalance};
Expand Down Expand Up @@ -229,6 +233,8 @@ pub enum WithdrawnFee<T: frame_system::Config, F: Balanced<AccountIdOf<T>>> {
///
pub struct SubtensorTxFeeHandler<F, OU>(PhantomData<(F, OU)>);

pub struct SubtensorEvmFeeHandler<F, OU>(PhantomData<(F, OU)>);

/// This implementation contains the list of calls that require paying transaction
/// fees in Alpha
impl<F, OU> SubtensorTxFeeHandler<F, OU> {
Expand Down Expand Up @@ -439,3 +445,78 @@ where
F::minimum_balance()
}
}

impl<T, F, OU> OnChargeEVMTransaction<T> for SubtensorEvmFeeHandler<F, OU>
where
T: EvmConfig + pallet_subtensor::Config,
F: Balanced<T::AccountId>,
OU: OnUnbalanced<Credit<T::AccountId, F>>,
T::AddressMapping: AddressMapping<T::AccountId>,
<F as Inspect<T::AccountId>>::Balance: From<TaoBalance> + Into<TaoBalance>,
{
type LiquidityInfo = Option<Credit<T::AccountId, F>>;

fn withdraw_fee(
who: &H160,
fee: EvmBalance,
) -> Result<Self::LiquidityInfo, pallet_evm::Error<T>> {
if fee.into_u256().is_zero() {
return Ok(None);
}

let account_id = <T::AddressMapping as AddressMapping<T::AccountId>>::into_account_id(*who);
let fee_sub = T::BalanceConverter::into_substrate_balance(fee)
.ok_or(pallet_evm::Error::<T>::FeeOverflow)?;

let imbalance = F::withdraw(
&account_id,
TaoBalance::from(fee_sub.into_u64_saturating()).into(),
Precision::Exact,
frame_support::traits::tokens::Preservation::Preserve,
frame_support::traits::tokens::Fortitude::Polite,
)
.map_err(|_| pallet_evm::Error::<T>::BalanceLow)?;

Ok(Some(imbalance))
}

fn correct_and_deposit_fee(
who: &H160,
corrected_fee: EvmBalance,
base_fee: EvmBalance,
already_withdrawn: Self::LiquidityInfo,
) -> Self::LiquidityInfo {
if let Some(paid) = already_withdrawn {
let account_id =
<T::AddressMapping as AddressMapping<T::AccountId>>::into_account_id(*who);
let corrected_fee_sub = T::BalanceConverter::into_substrate_balance(corrected_fee)
.unwrap_or_else(|| 0u64.into());
let refund_amount = paid
.peek()
.saturating_sub(TaoBalance::from(corrected_fee_sub.into_u64_saturating()).into());
let refund_imbalance = F::deposit(&account_id, refund_amount, Precision::BestEffort)
.unwrap_or_else(|_| Debt::<T::AccountId, F>::zero());
let adjusted_paid = paid
.offset(refund_imbalance)
.same()
.unwrap_or_else(|_| Credit::<T::AccountId, F>::zero());
let base_fee_sub = T::BalanceConverter::into_substrate_balance(base_fee)
.unwrap_or_else(|| 0u64.into());
let (base_fee_credit, tip) =
adjusted_paid.split(TaoBalance::from(base_fee_sub.into_u64_saturating()).into());
OU::on_unbalanced(base_fee_credit);
return Some(tip);
}

None
}

fn pay_priority_fee(tip: Self::LiquidityInfo) {
if let Some(tip) = tip {
let author = <T::AddressMapping as AddressMapping<T::AccountId>>::into_account_id(
pallet_evm::Pallet::<T>::find_author(),
);
let _ = F::resolve(&author, tip);
}
}
}
8 changes: 5 additions & 3 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ use pallet_transaction_payment::{ConstFeeMultiplier, Multiplier};
#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;
pub use sp_runtime::{Perbill, Permill};
use subtensor_transaction_fee::{SubtensorTxFeeHandler, TransactionFeeHandler};
use subtensor_transaction_fee::{
SubtensorEvmFeeHandler, SubtensorTxFeeHandler, TransactionFeeHandler,
};

use core::marker::PhantomData;

Expand Down Expand Up @@ -272,7 +274,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
// `spec_version`, and `authoring_version` are the same between Wasm and native.
// This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
// the compatible custom types.
spec_version: 406,
spec_version: 407,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
Expand Down Expand Up @@ -1400,7 +1402,7 @@ impl pallet_evm::Config for Runtime {
type ChainId = ConfigurableChainId;
type BlockGasLimit = BlockGasLimit;
type Runner = pallet_evm::runner::stack::Runner<Self>;
type OnChargeTransaction = ();
type OnChargeTransaction = SubtensorEvmFeeHandler<Balances, TransactionFeeHandler<Runtime>>;
type OnCreate = ();
type FindAuthor = FindAuthorTruncated<Aura>;
type GasLimitPovSizeRatio = GasLimitPovSizeRatio;
Expand Down
94 changes: 94 additions & 0 deletions runtime/tests/evm_transaction_fee.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#![allow(clippy::expect_used, clippy::unwrap_used)]

use codec::Encode;
use frame_support::traits::fungible::Inspect;
use node_subtensor_runtime::{Aura, Balances, BuildStorage, Runtime, RuntimeGenesisConfig};
use pallet_evm::{AddressMapping, EvmBalance, OnChargeEVMTransaction};
use sp_consensus_aura::{AURA_ENGINE_ID, sr25519::AuthorityId as AuraId};
use sp_core::H160;
use sp_core::sr25519;
use subtensor_runtime_common::{AuthorshipInfo, TaoBalance};

fn new_test_ext() -> sp_io::TestExternalities {
sp_tracing::try_init_simple();
let mut ext: sp_io::TestExternalities = RuntimeGenesisConfig {
..Default::default()
}
.build_storage()
.unwrap()
.into();
ext.execute_with(|| frame_system::Pallet::<Runtime>::set_block_number(1));
ext
}

fn add_balance_to_coldkey_account(coldkey: &sp_core::crypto::AccountId32, tao: TaoBalance) {
let credit = pallet_subtensor::Pallet::<Runtime>::mint_tao(tao);
let _ = pallet_subtensor::Pallet::<Runtime>::spend_tao(coldkey, credit, tao).unwrap();
}

fn initialize_block_with_aura_authority(authority: AuraId, slot: u64) {
Aura::change_authorities(vec![authority].try_into().unwrap());
let digest = sp_runtime::Digest {
logs: vec![sp_runtime::DigestItem::PreRuntime(
AURA_ENGINE_ID,
slot.encode(),
)],
};
frame_system::Pallet::<Runtime>::initialize(&1u32.into(), &Default::default(), &digest);
}

#[test]
fn evm_fee_refund_does_not_change_total_issuance() {
new_test_ext().execute_with(|| {
initialize_block_with_aura_authority(AuraId::from(sr25519::Public::from_raw([1u8; 32])), 0);

let evm_addr = H160::from_low_u64_be(7);
let account_id = <Runtime as pallet_evm::Config>::AddressMapping::into_account_id(evm_addr);
let substrate_author = <Runtime as AuthorshipInfo<sp_runtime::AccountId32>>::author()
.expect("aura digest should provide a substrate block author");
let evm_author =
<Runtime as pallet_evm::Config>::AddressMapping::into_account_id(pallet_evm::Pallet::<
Runtime,
>::find_author(
));

add_balance_to_coldkey_account(&account_id, 1_000_000_000u64.into());
add_balance_to_coldkey_account(&substrate_author, 1_000_000_000u64.into());
add_balance_to_coldkey_account(&evm_author, 1_000_000_000u64.into());

let balances_issuance_before = Balances::total_issuance();
let subtensor_issuance_before = pallet_subtensor::Pallet::<Runtime>::get_total_issuance();
let balance_before = Balances::total_balance(&account_id);

assert_eq!(balances_issuance_before, subtensor_issuance_before);

let withdrawn =
<<Runtime as pallet_evm::Config>::OnChargeTransaction as OnChargeEVMTransaction<
Runtime,
>>::withdraw_fee(&evm_addr, EvmBalance::from(10_000_000_000u128))
.unwrap();

let tip =
<<Runtime as pallet_evm::Config>::OnChargeTransaction as OnChargeEVMTransaction<
Runtime,
>>::correct_and_deposit_fee(
&evm_addr,
EvmBalance::from(5_000_000_000u128),
EvmBalance::from(3_000_000_000u128),
withdrawn,
);

<<Runtime as pallet_evm::Config>::OnChargeTransaction as OnChargeEVMTransaction<
Runtime,
>>::pay_priority_fee(tip);

assert_eq!(
Balances::total_issuance(),
pallet_subtensor::Pallet::<Runtime>::get_total_issuance()
);
assert_eq!(
Balances::total_balance(&account_id),
balance_before - TaoBalance::from(5)
);
});
}
Loading