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

Sovereign EVM balances layer #78

Merged
merged 6 commits into from
Oct 30, 2023
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
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 @@ -171,6 +172,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