Skip to content

Commit

Permalink
Sovereign EVM balances layer (#124)
Browse files Browse the repository at this point in the history
* Sovereign EVM balances layer (#109)

* Sovereign EVM balances layer (#100)

* Sovereign EVM balances layer (#95)

* Sovereign EVM balances layer (#87)

* Frame EVM balances (#65)

* Add initital frame balances structure

* Add account data balances logic

* Define main types

* Add imbalances logic

* Add DustCleaner

* Implement balances related operations

* Implement currencies for the pallet

* Implement Inspect for the pallet

* Make account_data mod private

* Leave only free balance data for account

* Support try-runtime features

* Apply formatting

* Fix comment

* Add mock with evm, evm-system, evm-balances configs

* Add basic setup test

* Add fee deduction test

* Add issuance_after_tip test

* Add refunds_should_work test

* Add refunds_and_priority_should_work test

* Fix clippy in tests

* Fix basec setup works test with evm balances checks

* Remove redundant set block in tests

* Add call_should_fail_with_priority_greater_than_max_fee test

* Add call_should_succeed_with_priority_equal_to_max_fee test

* Use EvmSystem as AccountProvider in tests

* Add account_should_be_reaped test

* Add deposit_into_existing test

* Add balance_transfer_works test

* Add slashing_balance_works test

* Add withdraw_balance_works test

* Add transferring_too_high_value_should_not_panic test

* Rename test to transfer_works

* Add basic tests for currency

* Add burn and issue related tests

* Add deposit_creating_works test

* Add currency_make_free_balance_be test

* Rename evm logic related tests

* Fix comment

* Rename slashing related test

* Rename test with make free balance

* Rename test with transferring too high value

* Assert evm system account existence for currency_deposit_creating_works test

* Add EvmSystem events check

* Remove license

* Use workspace dep

* Fix mock

* Remove deprecated trait Store

* Remove deprecated storage getter

* Add Apache-2.0 license

* Fix tests

* Apply required changes for fungible inspect trait

* Support `Mutate`, `Unbalanced`, `Balanced` fungible related traits for `pallet-evm-balances` (#102)

* Move currencies implementation into separate mod

* [substrate=apply] Deprecate Currency; introduce holds and freezing into fungible traits #12951

* Apply new balances logic to currency trait implementation

* Use DustRemoval over Credit instead of NegativeImbalance

* Implement Balanced, Unbalanced, Mutate fungible traits for pallet

* Revert using negative imbalance

* Apply formatter

* Fix withdraw_consequence method

* Move currency related tests to separate mod

* Add transfer_fails_funds_unavailable test to currency tests

* Add transfer_works_full_balance test to currency tests

* Fix slashing conditions

* Add slash_works_full_balance test to currency tests

* Add deposit_into_existing related fails tests

* Add withdraw_works_full_balance test to currency tests

* Add withdraw fails related tests to currency tests

* Add basic fungible tests

* Add reducable balance test to fungible tests

* Add can deposit related tests

* Fix can_withdraw logic

* Add can_withdraw related tests

* Add write_balance_works test

* Add set_total_issuance_works test

* Add decrease_balance related tests

* Add increase_balance related tests

* Add deactivate_reactivate_works test

* Add mint_into related tests

* Add burn_from related tests

* Add shelve related tests

* Add restored related tests

* Add transfer related tests

* Add balanced related tests

* Undo formatting

* Simplify reducible logic implementation

* Simplify can_deposit implementation

* Simplify can_withdraw implementation

* Properly use semantics of total and free balances

* Improve reducable_balance_works test

* Fix test race conditions

* Fix mock

* Apply formatter

* Fungible conformance tests: Inspect and Mutate (#110)

* Use u64 for evm system accounts at mock

* Apply required changes to current tests

* Include fungible conformance tests

* Add asserting total issuance invariant in tests
  • Loading branch information
dmitrylavrenov committed Jun 11, 2024
1 parent f95f51c commit 70b4b48
Show file tree
Hide file tree
Showing 13 changed files with 3,309 additions and 0 deletions.
20 changes: 20 additions & 0 deletions Cargo.lock

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

3 changes: 3 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 @@ -65,6 +66,7 @@ mockall = "0.11"
num_enum = { version = "0.6.1", default-features = false }
parity-db = "0.4.10"
parking_lot = "0.12.1"
paste = "1.0"
rlp = { version = "0.5.2", default-features = false }
scale-codec = { package = "parity-scale-codec", version = "3.6.4", default-features = false, features = ["derive"] }
scale-info = { version = "2.9.0", default-features = false, features = ["derive"] }
Expand Down Expand Up @@ -169,6 +171,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."
edition = { workspace = true }
repository = { workspace = true }

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

[dependencies]
log = { workspace = true, 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 }
paste = { 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",
]
66 changes: 66 additions & 0 deletions frame/evm-balances/src/account_data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//! 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

0 comments on commit 70b4b48

Please sign in to comment.