Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/handle all decimal conversions #8

Merged
Merged
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
36 changes: 35 additions & 1 deletion frame/ethereum/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use sp_runtime::{
AccountId32, BuildStorage,
};
// Frontier
use pallet_evm::{AddressMapping, EnsureAddressTruncated, FeeCalculator};
use pallet_evm::{AddressMapping, BalanceConverter, EnsureAddressTruncated, FeeCalculator};

use super::*;
use crate::IntermediateStateRoot;
Expand Down Expand Up @@ -158,8 +158,42 @@ parameter_types! {
pub SuicideQuickClearLimit: u32 = 0;
}

const EVM_DECIMALS_FACTOR: u64 = 1_000_000_000_u64;
pub struct SubtensorEvmBalanceConverter;

impl BalanceConverter for SubtensorEvmBalanceConverter {
/// Convert from Substrate balance (u64) to EVM balance (U256)
fn into_evm_balance(value: U256) -> Option<U256> {
value
.checked_mul(U256::from(EVM_DECIMALS_FACTOR))
.and_then(|evm_value| {
// Ensure the result fits within the maximum U256 value
if evm_value <= U256::MAX {
Some(evm_value)
} else {
None
}
})
}

/// Convert from EVM balance (U256) to Substrate balance (u64)
fn into_substrate_balance(value: U256) -> Option<U256> {
value
.checked_div(U256::from(EVM_DECIMALS_FACTOR))
.and_then(|substrate_value| {
// Ensure the result fits within the TAO balance type (u64)
if substrate_value <= U256::from(u64::MAX) {
Some(substrate_value)
} else {
None
}
})
}
}

impl pallet_evm::Config for Test {
type FeeCalculator = FixedGasPrice;
type BalanceConverter = SubtensorEvmBalanceConverter;
type GasWeightMapping = pallet_evm::FixedGasWeightMapping<Self>;
type WeightPerGas = WeightPerGas;
type BlockHashMapping = crate::EthereumBlockHashMapping<Self>;
Expand Down
2 changes: 1 addition & 1 deletion frame/ethereum/src/tests/eip1559.rs
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,7 @@ fn validated_transaction_apply_zero_gas_price_works() {
max_fee_per_gas: U256::zero(),
gas_limit: U256::from(21_000),
action: ethereum::TransactionAction::Call(bob.address),
value: U256::from(100),
value: U256::from(100e9 as u128),
input: Default::default(),
}
.sign(&alice.private_key, None);
Expand Down
2 changes: 1 addition & 1 deletion frame/ethereum/src/tests/eip2930.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ fn validated_transaction_apply_zero_gas_price_works() {
gas_price: U256::zero(),
gas_limit: U256::from(21_000),
action: ethereum::TransactionAction::Call(bob.address),
value: U256::from(100),
value: U256::from(100e9 as u128),
input: Default::default(),
}
.sign(&alice.private_key, None);
Expand Down
2 changes: 1 addition & 1 deletion frame/ethereum/src/tests/legacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ fn validated_transaction_apply_zero_gas_price_works() {
gas_price: U256::zero(),
gas_limit: U256::from(21_000),
action: ethereum::TransactionAction::Call(bob.address),
value: U256::from(100),
value: U256::from(100e9 as u128),
input: Default::default(),
}
.sign(&alice.private_key);
Expand Down
39 changes: 37 additions & 2 deletions frame/evm/precompile/dispatch/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ use sp_runtime::traits::{BlakeTwo256, IdentityLookup};

use fp_evm::{ExitError, ExitReason, Transfer};
use pallet_evm::{
Context, EnsureAddressNever, EnsureAddressRoot, FeeCalculator, IdentityAddressMapping,
PrecompileHandle,
BalanceConverter, Context, EnsureAddressNever, EnsureAddressRoot, FeeCalculator,
IdentityAddressMapping, PrecompileHandle,
};

frame_support::construct_runtime! {
Expand Down Expand Up @@ -121,6 +121,39 @@ impl FeeCalculator for FixedGasPrice {
}
}

const EVM_DECIMALS_FACTOR: u64 = 1_000_000_000_u64;
pub struct SubtensorEvmBalanceConverter;

impl BalanceConverter for SubtensorEvmBalanceConverter {
/// Convert from Substrate balance (u64) to EVM balance (U256)
fn into_evm_balance(value: U256) -> Option<U256> {
value
.checked_mul(U256::from(EVM_DECIMALS_FACTOR))
.and_then(|evm_value| {
// Ensure the result fits within the maximum U256 value
if evm_value <= U256::MAX {
Some(evm_value)
} else {
None
}
})
}

/// Convert from EVM balance (U256) to Substrate balance (u64)
fn into_substrate_balance(value: U256) -> Option<U256> {
value
.checked_div(U256::from(EVM_DECIMALS_FACTOR))
.and_then(|substrate_value| {
// Ensure the result fits within the TAO balance type (u64)
if substrate_value <= U256::from(u64::MAX) {
Some(substrate_value)
} else {
None
}
})
}
}

pub struct FindAuthorTruncated;
impl FindAuthor<H160> for FindAuthorTruncated {
fn find_author<'a, I>(_digests: I) -> Option<H160>
Expand All @@ -147,6 +180,8 @@ impl pallet_evm::Config for Test {
type AddressMapping = IdentityAddressMapping;
type Currency = Balances;

type BalanceConverter = SubtensorEvmBalanceConverter;

type RuntimeEvent = RuntimeEvent;
type PrecompilesType = ();
type PrecompilesValue = ();
Expand Down
36 changes: 35 additions & 1 deletion frame/evm/precompile/storage-cleaner/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

use crate::{StorageCleanerPrecompile, StorageCleanerPrecompileCall};
use frame_support::{parameter_types, weights::Weight};
use pallet_evm::{EnsureAddressNever, EnsureAddressRoot, IdentityAddressMapping};
use pallet_evm::{BalanceConverter, EnsureAddressNever, EnsureAddressRoot, IdentityAddressMapping};
use precompile_utils::{precompile_set::*, testing::*};
use sp_core::{ConstU32, H256, U256};
use sp_runtime::{
Expand Down Expand Up @@ -123,7 +123,41 @@ parameter_types! {
pub SuicideQuickClearLimit: u32 = 0;
}

const EVM_DECIMALS_FACTOR: u64 = 1_000_000_000_u64;
pub struct SubtensorEvmBalanceConverter;

impl BalanceConverter for SubtensorEvmBalanceConverter {
/// Convert from Substrate balance (u64) to EVM balance (U256)
fn into_evm_balance(value: U256) -> Option<U256> {
value
.checked_mul(U256::from(EVM_DECIMALS_FACTOR))
.and_then(|evm_value| {
// Ensure the result fits within the maximum U256 value
if evm_value <= U256::MAX {
Some(evm_value)
} else {
None
}
})
}

/// Convert from EVM balance (U256) to Substrate balance (u64)
fn into_substrate_balance(value: U256) -> Option<U256> {
value
.checked_div(U256::from(EVM_DECIMALS_FACTOR))
.and_then(|substrate_value| {
// Ensure the result fits within the TAO balance type (u64)
if substrate_value <= U256::from(u64::MAX) {
Some(substrate_value)
} else {
None
}
})
}
}

impl pallet_evm::Config for Runtime {
type BalanceConverter = SubtensorEvmBalanceConverter;
type FeeCalculator = ();
type GasWeightMapping = pallet_evm::FixedGasWeightMapping<Self>;
type WeightPerGas = WeightPerGas;
Expand Down
55 changes: 39 additions & 16 deletions frame/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -951,7 +951,8 @@ impl<T: Config> Pallet<T> {
let balance =
T::Currency::reducible_balance(&account_id, Preservation::Preserve, Fortitude::Polite);
let balance_u256 = U256::from(UniqueSaturatedInto::<u128>::unique_saturated_into(balance));
let balance_eth = T::BalanceConverter::into_evm_balance(balance_u256).unwrap_or(U256::from(0));
let balance_eth =
T::BalanceConverter::into_evm_balance(balance_u256).unwrap_or(U256::from(0));

(
Account {
Expand Down Expand Up @@ -1027,7 +1028,8 @@ where
let account_id = T::AddressMapping::into_account_id(*who);

// Recalculate fee decimals using BalanceConverter
let fee_sub = T::BalanceConverter::into_substrate_balance(fee).ok_or(Error::<T>::FeeOverflow)?;
let fee_sub =
T::BalanceConverter::into_substrate_balance(fee).ok_or(Error::<T>::FeeOverflow)?;

let imbalance = C::withdraw(
&account_id,
Expand All @@ -1036,22 +1038,27 @@ where
ExistenceRequirement::AllowDeath,
)
.map_err(|_| Error::<T>::BalanceLow)?;
Ok(Some(imbalance))
Ok(Some(imbalance)) // Returns substrate balance
}

fn correct_and_deposit_fee(
who: &H160,
corrected_fee: U256,
base_fee: U256,
already_withdrawn: Self::LiquidityInfo,
already_withdrawn: Self::LiquidityInfo, // Expects substrate balance
) -> Self::LiquidityInfo {
if let Some(paid) = already_withdrawn {
let account_id = T::AddressMapping::into_account_id(*who);

// Convert corrected fee into substrate balance
let corrected_fee_sub =
T::BalanceConverter::into_substrate_balance(corrected_fee).unwrap_or(U256::from(0));

// Calculate how much refund we should return
let refund_amount = paid
.peek()
.saturating_sub(corrected_fee.unique_saturated_into());
.saturating_sub(corrected_fee_sub.unique_saturated_into());

// refund to the account that paid the fees. If this fails, the
// account might have dropped below the existential balance. In
// that case we don't refund anything.
Expand Down Expand Up @@ -1082,15 +1089,20 @@ where
.same()
.unwrap_or_else(|_| C::NegativeImbalance::zero());

let (base_fee, tip) = adjusted_paid.split(base_fee.unique_saturated_into());
// Convert base fee into substrate balance
let base_fee_sub =
T::BalanceConverter::into_substrate_balance(base_fee).unwrap_or(U256::from(0));

let (base_fee, tip) = adjusted_paid.split(base_fee_sub.unique_saturated_into());
// Handle base fee. Can be either burned, rationed, etc ...
OU::on_unbalanced(base_fee);
return Some(tip);
return Some(tip); // Returns substrate balance
}
None
}

fn pay_priority_fee(tip: Self::LiquidityInfo) {
// Expects substrate balance
// Default Ethereum behaviour: issue the tip to the block author.
if let Some(tip) = tip {
let account_id = T::AddressMapping::into_account_id(<Pallet<T>>::find_author());
Expand Down Expand Up @@ -1123,7 +1135,8 @@ where
let account_id = T::AddressMapping::into_account_id(*who);

// Recalculate fee decimals using BalanceConverter
let fee_sub = T::BalanceConverter::into_substrate_balance(fee).ok_or(Error::<T>::FeeOverflow)?;
let fee_sub =
T::BalanceConverter::into_substrate_balance(fee).ok_or(Error::<T>::FeeOverflow)?;

let imbalance = F::withdraw(
&account_id,
Expand All @@ -1133,22 +1146,26 @@ where
Fortitude::Polite,
)
.map_err(|_| Error::<T>::BalanceLow)?;
Ok(Some(imbalance))
Ok(Some(imbalance)) // Returns substrate balance
}

fn correct_and_deposit_fee(
who: &H160,
corrected_fee: U256,
base_fee: U256,
already_withdrawn: Self::LiquidityInfo,
already_withdrawn: Self::LiquidityInfo, // Expects substrate balance
) -> Self::LiquidityInfo {
if let Some(paid) = already_withdrawn {
let account_id = T::AddressMapping::into_account_id(*who);

// Convert corrected fee into substrate balance
let corrected_fee_sub =
T::BalanceConverter::into_substrate_balance(corrected_fee).unwrap_or(U256::from(0));

// Calculate how much refund we should return
let refund_amount = paid
.peek()
.saturating_sub(corrected_fee.unique_saturated_into());
.saturating_sub(corrected_fee_sub.unique_saturated_into());
// refund to the account that paid the fees.
let refund_imbalance = F::deposit(&account_id, refund_amount, Precision::BestEffort)
.unwrap_or_else(|_| Debt::<T::AccountId, F>::zero());
Expand All @@ -1159,15 +1176,20 @@ where
.same()
.unwrap_or_else(|_| Credit::<T::AccountId, F>::zero());

let (base_fee, tip) = adjusted_paid.split(base_fee.unique_saturated_into());
// Convert base fee into substrate balance
let base_fee_sub =
T::BalanceConverter::into_substrate_balance(base_fee).unwrap_or(U256::from(0));

let (base_fee, tip) = adjusted_paid.split(base_fee_sub.unique_saturated_into());
// Handle base fee. Can be either burned, rationed, etc ...
OU::on_unbalanced(base_fee);
return Some(tip);
return Some(tip); // Returns substrate balance
}
None
}

fn pay_priority_fee(tip: Self::LiquidityInfo) {
// Expects substrate balance
// Default Ethereum behaviour: issue the tip to the block author.
if let Some(tip) = tip {
let account_id = T::AddressMapping::into_account_id(<Pallet<T>>::find_author());
Expand Down Expand Up @@ -1236,10 +1258,11 @@ pub trait BalanceConverter {
fn into_substrate_balance(value: U256) -> Option<U256>;
}

impl BalanceConverter for ()
{
impl BalanceConverter for () {
fn into_evm_balance(value: U256) -> Option<U256> {
Some(U256::from(UniqueSaturatedInto::<u128>::unique_saturated_into(value)))
Some(U256::from(
UniqueSaturatedInto::<u128>::unique_saturated_into(value),
))
}

fn into_substrate_balance(value: U256) -> Option<U256> {
Expand Down
37 changes: 36 additions & 1 deletion frame/evm/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use sp_runtime::{
};

use crate::{
EnsureAddressNever, EnsureAddressRoot, FeeCalculator, IdentityAddressMapping,
BalanceConverter, EnsureAddressNever, EnsureAddressRoot, FeeCalculator, IdentityAddressMapping,
IsPrecompileResult, Precompile, PrecompileHandle, PrecompileResult, PrecompileSet,
};

Expand Down Expand Up @@ -133,7 +133,42 @@ parameter_types! {
pub MockPrecompiles: MockPrecompileSet = MockPrecompileSet;
pub SuicideQuickClearLimit: u32 = 0;
}

const EVM_DECIMALS_FACTOR: u64 = 1_000_000_000_u64;
pub struct SubtensorEvmBalanceConverter;

impl BalanceConverter for SubtensorEvmBalanceConverter {
/// Convert from Substrate balance (u64) to EVM balance (U256)
fn into_evm_balance(value: U256) -> Option<U256> {
value
.checked_mul(U256::from(EVM_DECIMALS_FACTOR))
.and_then(|evm_value| {
// Ensure the result fits within the maximum U256 value
if evm_value <= U256::MAX {
Some(evm_value)
} else {
None
}
})
}

/// Convert from EVM balance (U256) to Substrate balance (u64)
fn into_substrate_balance(value: U256) -> Option<U256> {
value
.checked_div(U256::from(EVM_DECIMALS_FACTOR))
.and_then(|substrate_value| {
// Ensure the result fits within the TAO balance type (u64)
if substrate_value <= U256::from(u64::MAX) {
Some(substrate_value)
} else {
None
}
})
}
}

impl crate::Config for Test {
type BalanceConverter = SubtensorEvmBalanceConverter;
type FeeCalculator = FixedGasPrice;
type GasWeightMapping = crate::FixedGasWeightMapping<Self>;
type WeightPerGas = WeightPerGas;
Expand Down
Loading