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

Frame EVM balances #65

Merged
merged 43 commits into from
Jun 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
a6e2ce2
Add initital frame balances structure
dmitrylavrenov May 16, 2023
c7fd240
Add account data balances logic
dmitrylavrenov May 16, 2023
0f76b9a
Define main types
dmitrylavrenov May 16, 2023
4f31e10
Add imbalances logic
dmitrylavrenov May 16, 2023
3531801
Add DustCleaner
dmitrylavrenov May 16, 2023
af57f3a
Implement balances related operations
dmitrylavrenov May 16, 2023
7f321c3
Implement currencies for the pallet
dmitrylavrenov May 16, 2023
7a9ca5e
Implement Inspect for the pallet
dmitrylavrenov May 16, 2023
1bcec1e
Make account_data mod private
dmitrylavrenov May 17, 2023
f49e173
Leave only free balance data for account
dmitrylavrenov May 24, 2023
31d8301
Support try-runtime features
dmitrylavrenov May 29, 2023
27faf1d
Apply formatting
dmitrylavrenov May 30, 2023
939c4ed
Fix comment
dmitrylavrenov May 30, 2023
533a735
Add mock with evm, evm-system, evm-balances configs
dmitrylavrenov May 30, 2023
3800686
Add basic setup test
dmitrylavrenov May 30, 2023
9d3b6c2
Add fee deduction test
dmitrylavrenov May 30, 2023
d730d01
Add issuance_after_tip test
dmitrylavrenov May 31, 2023
c1f198c
Add refunds_should_work test
dmitrylavrenov May 31, 2023
2937fc3
Add refunds_and_priority_should_work test
dmitrylavrenov May 31, 2023
ccc5d22
Fix clippy in tests
dmitrylavrenov May 31, 2023
307d484
Fix basec setup works test with evm balances checks
dmitrylavrenov Jun 1, 2023
dd3044a
Remove redundant set block in tests
dmitrylavrenov Jun 1, 2023
87f457c
Add call_should_fail_with_priority_greater_than_max_fee test
dmitrylavrenov Jun 1, 2023
67c5961
Add call_should_succeed_with_priority_equal_to_max_fee test
dmitrylavrenov Jun 1, 2023
5e5060b
Use EvmSystem as AccountProvider in tests
dmitrylavrenov Jun 19, 2023
52fef63
Add account_should_be_reaped test
dmitrylavrenov Jun 19, 2023
3953750
Add deposit_into_existing test
dmitrylavrenov Jun 19, 2023
3741cb9
Add balance_transfer_works test
dmitrylavrenov Jun 19, 2023
d121519
Add slashing_balance_works test
dmitrylavrenov Jun 19, 2023
f1ba4cc
Add withdraw_balance_works test
dmitrylavrenov Jun 19, 2023
1c9e183
Add transferring_too_high_value_should_not_panic test
dmitrylavrenov Jun 19, 2023
6581eb5
Rename test to transfer_works
dmitrylavrenov Jun 19, 2023
71f5fed
Add basic tests for currency
dmitrylavrenov Jun 19, 2023
6b61ee4
Add burn and issue related tests
dmitrylavrenov Jun 19, 2023
3b19e54
Add deposit_creating_works test
dmitrylavrenov Jun 19, 2023
36c4a3e
Add currency_make_free_balance_be test
dmitrylavrenov Jun 19, 2023
91a600e
Rename evm logic related tests
dmitrylavrenov Jun 19, 2023
da78ae8
Fix comment
dmitrylavrenov Jun 19, 2023
c43f3e0
Rename slashing related test
dmitrylavrenov Jun 19, 2023
ac01a02
Rename test with make free balance
dmitrylavrenov Jun 19, 2023
294eb6d
Rename test with transferring too high value
dmitrylavrenov Jun 19, 2023
9ccbaf9
Assert evm system account existence for currency_deposit_creating_wor…
dmitrylavrenov Jun 19, 2023
30d164e
Add EvmSystem events check
dmitrylavrenov Jun 19, 2023
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
19 changes: 19 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ members = [
"frame/dynamic-fee",
"frame/ethereum",
"frame/evm",
"frame/evm-balances",
"frame/evm-chain-id",
"frame/evm-system",
"frame/hotfix-sufficients",
Expand Down Expand Up @@ -137,6 +138,7 @@ pallet-base-fee = { version = "1.0.0", path = "frame/base-fee", default-features
pallet-dynamic-fee = { version = "4.0.0-dev", path = "frame/dynamic-fee", default-features = false }
pallet-ethereum = { version = "4.0.0-dev", path = "frame/ethereum", default-features = false }
pallet-evm = { version = "6.0.0-dev", path = "frame/evm", default-features = false }
pallet-evm-balances = { version = "1.0.0-dev", path = "frame/evm-balances", default-features = false }
pallet-evm-chain-id = { version = "1.0.0-dev", path = "frame/evm-chain-id", default-features = false }
pallet-evm-system = { version = "1.0.0-dev", path = "frame/evm-system", default-features = false }
pallet-evm-precompile-modexp = { version = "2.0.0-dev", path = "frame/evm/precompile/modexp", default-features = false }
Expand Down
51 changes: 51 additions & 0 deletions frame/evm-balances/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
[package]
name = "pallet-evm-balances"
version = "1.0.0-dev"
license = "Apache-2.0"
description = "FRAME EVM BALANCES pallet."
authors = { workspace = true }
edition = { workspace = true }
repository = { workspace = true }

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
log = { version = "0.4.17", default-features = false }
scale-codec = { package = "parity-scale-codec", workspace = true }
scale-info = { workspace = true }
# Substrate
frame-support = { workspace = true }
frame-system = { workspace = true }
sp-runtime = { workspace = true }
sp-std = { workspace = true }

[dev-dependencies]
fp-evm = { workspace = true }
pallet-evm = { workspace = true }
pallet-evm-system = { workspace = true }
pallet-timestamp = { workspace = true }
sp-core = { workspace = true }
sp-io = { workspace = true }

[features]
default = ["std"]
std = [
"log/std",
"scale-codec/std",
"scale-info/std",
# Substrate
"frame-support/std",
"frame-system/std",
"pallet-timestamp/std",
"sp-runtime/std",
"sp-std/std",
# Frontier
"fp-evm/std",
"pallet-evm/std",
"pallet-evm-system/std",
]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
]
46 changes: 46 additions & 0 deletions frame/evm-balances/src/account_data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//! Account balances logic.

use frame_support::traits::WithdrawReasons;

use super::*;

/// All balance information for an account.
#[derive(Encode, Decode, Clone, PartialEq, Eq, Default, RuntimeDebug, MaxEncodedLen, TypeInfo)]
pub struct AccountData<Balance> {
/// Non-reserved part of the balance. There may still be restrictions on this, but it is the
/// total pool what may in principle be transferred, reserved and used for tipping.
///
/// This is the only balance that matters in terms of most operations on tokens. It
/// alone is used to determine the balance when in the contract execution environment.
pub free: Balance,
}

impl<Balance: Copy> AccountData<Balance> {
/// The total balance in this account.
pub(crate) fn total(&self) -> Balance {
self.free
}
}

/// Simplified reasons for withdrawing balance.
#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, MaxEncodedLen, TypeInfo)]
pub enum Reasons {
/// Paying system transaction fees.
Fee = 0,
/// Any reason other than paying system transaction fees.
Misc = 1,
/// Any reason at all.
All = 2,
}

impl From<WithdrawReasons> for Reasons {
fn from(r: WithdrawReasons) -> Reasons {
if r == WithdrawReasons::TRANSACTION_PAYMENT {
Reasons::Fee
} else if r.contains(WithdrawReasons::TRANSACTION_PAYMENT) {
Reasons::All
} else {
Reasons::Misc
}
}
}
172 changes: 172 additions & 0 deletions frame/evm-balances/src/imbalances.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
//! Imbalances implementation.

use frame_support::traits::{SameOrOther, TryDrop};
use sp_std::{cmp::Ordering, mem};

use super::*;

/// Opaque, move-only struct with private fields that serves as a token denoting that
/// funds have been created without any equal and opposite accounting.
#[must_use]
#[derive(RuntimeDebug, PartialEq, Eq)]
pub struct PositiveImbalance<T: Config<I>, I: 'static = ()>(T::Balance);

impl<T: Config<I>, I: 'static> PositiveImbalance<T, I> {
/// Create a new positive imbalance from a balance.
pub fn new(amount: T::Balance) -> Self {
PositiveImbalance(amount)
}
}

/// Opaque, move-only struct with private fields that serves as a token denoting that
/// funds have been destroyed without any equal and opposite accounting.
#[must_use]
#[derive(RuntimeDebug, PartialEq, Eq)]
pub struct NegativeImbalance<T: Config<I>, I: 'static = ()>(T::Balance);

impl<T: Config<I>, I: 'static> NegativeImbalance<T, I> {
/// Create a new negative imbalance from a balance.
pub fn new(amount: T::Balance) -> Self {
NegativeImbalance(amount)
}
}

impl<T: Config<I>, I: 'static> TryDrop for PositiveImbalance<T, I> {
fn try_drop(self) -> result::Result<(), Self> {
self.drop_zero()
}
}

impl<T: Config<I>, I: 'static> Default for PositiveImbalance<T, I> {
fn default() -> Self {
Self::zero()
}
}

impl<T: Config<I>, I: 'static> Imbalance<T::Balance> for PositiveImbalance<T, I> {
type Opposite = NegativeImbalance<T, I>;

fn zero() -> Self {
Self(Zero::zero())
}

fn drop_zero(self) -> result::Result<(), Self> {
if self.0.is_zero() {
Ok(())
} else {
Err(self)
}
}

fn split(self, amount: T::Balance) -> (Self, Self) {
let first = self.0.min(amount);
let second = self.0 - first;

mem::forget(self);
(Self(first), Self(second))
}

fn merge(mut self, other: Self) -> Self {
self.0 = self.0.saturating_add(other.0);
mem::forget(other);

self
}

fn subsume(&mut self, other: Self) {
self.0 = self.0.saturating_add(other.0);
mem::forget(other);
}

fn offset(self, other: Self::Opposite) -> SameOrOther<Self, Self::Opposite> {
let (a, b) = (self.0, other.0);
mem::forget((self, other));

match a.cmp(&b) {
Ordering::Greater => SameOrOther::Same(Self(a - b)),
Ordering::Less => SameOrOther::Other(NegativeImbalance::new(b - a)),
Ordering::Equal => SameOrOther::None,
}
}

fn peek(&self) -> T::Balance {
self.0
}
}

impl<T: Config<I>, I: 'static> TryDrop for NegativeImbalance<T, I> {
fn try_drop(self) -> result::Result<(), Self> {
self.drop_zero()
}
}

impl<T: Config<I>, I: 'static> Default for NegativeImbalance<T, I> {
fn default() -> Self {
Self::zero()
}
}

impl<T: Config<I>, I: 'static> Imbalance<T::Balance> for NegativeImbalance<T, I> {
type Opposite = PositiveImbalance<T, I>;

fn zero() -> Self {
Self(Zero::zero())
}

fn drop_zero(self) -> result::Result<(), Self> {
if self.0.is_zero() {
Ok(())
} else {
Err(self)
}
}

fn split(self, amount: T::Balance) -> (Self, Self) {
let first = self.0.min(amount);
let second = self.0 - first;

mem::forget(self);
(Self(first), Self(second))
}

fn merge(mut self, other: Self) -> Self {
self.0 = self.0.saturating_add(other.0);
mem::forget(other);

self
}

fn subsume(&mut self, other: Self) {
self.0 = self.0.saturating_add(other.0);
mem::forget(other);
}

fn offset(self, other: Self::Opposite) -> SameOrOther<Self, Self::Opposite> {
let (a, b) = (self.0, other.0);
mem::forget((self, other));

match a.cmp(&b) {
Ordering::Greater => SameOrOther::Same(Self(a - b)),
Ordering::Less => SameOrOther::Other(PositiveImbalance::new(b - a)),
Ordering::Equal => SameOrOther::None,
}
}

fn peek(&self) -> T::Balance {
self.0
}
}

impl<T: Config<I>, I: 'static> Drop for PositiveImbalance<T, I> {
/// Basic drop handler will just square up the total issuance.
fn drop(&mut self) {
TotalIssuance::<T, I>::mutate(|v| *v = v.saturating_add(self.0));
}
}

impl<T: Config<I>, I: 'static> Drop for NegativeImbalance<T, I> {
/// Basic drop handler will just square up the total issuance.
fn drop(&mut self) {
TotalIssuance::<T, I>::mutate(|v| *v = v.saturating_sub(self.0));
}
}
Loading