Skip to content

Commit c1d2652

Browse files
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
1 parent f95f51c commit c1d2652

12 files changed

+3097
-0
lines changed

Cargo.lock

+19
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ members = [
44
"frame/dynamic-fee",
55
"frame/ethereum",
66
"frame/evm",
7+
"frame/evm-balances",
78
"frame/evm-chain-id",
89
"frame/evm-system",
910
"frame/hotfix-sufficients",
@@ -169,6 +170,7 @@ pallet-base-fee = { version = "1.0.0", path = "frame/base-fee", default-features
169170
pallet-dynamic-fee = { version = "4.0.0-dev", path = "frame/dynamic-fee", default-features = false }
170171
pallet-ethereum = { version = "4.0.0-dev", path = "frame/ethereum", default-features = false }
171172
pallet-evm = { version = "6.0.0-dev", path = "frame/evm", default-features = false }
173+
pallet-evm-balances = { version = "1.0.0-dev", path = "frame/evm-balances", default-features = false }
172174
pallet-evm-chain-id = { version = "1.0.0-dev", path = "frame/evm-chain-id", default-features = false }
173175
pallet-evm-system = { version = "1.0.0-dev", path = "frame/evm-system", default-features = false }
174176
pallet-evm-precompile-modexp = { version = "2.0.0-dev", path = "frame/evm/precompile/modexp", default-features = false }

frame/evm-balances/Cargo.toml

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
[package]
2+
name = "pallet-evm-balances"
3+
version = "1.0.0-dev"
4+
license = "Apache-2.0"
5+
description = "FRAME EVM BALANCES pallet."
6+
edition = { workspace = true }
7+
repository = { workspace = true }
8+
9+
[package.metadata.docs.rs]
10+
targets = ["x86_64-unknown-linux-gnu"]
11+
12+
[dependencies]
13+
log = { workspace = true, default-features = false }
14+
scale-codec = { package = "parity-scale-codec", workspace = true }
15+
scale-info = { workspace = true }
16+
# Substrate
17+
frame-support = { workspace = true }
18+
frame-system = { workspace = true }
19+
sp-runtime = { workspace = true }
20+
sp-std = { workspace = true }
21+
22+
[dev-dependencies]
23+
fp-evm = { workspace = true }
24+
pallet-evm = { workspace = true }
25+
pallet-evm-system = { workspace = true }
26+
pallet-timestamp = { workspace = true }
27+
sp-core = { workspace = true }
28+
sp-io = { workspace = true }
29+
30+
[features]
31+
default = ["std"]
32+
std = [
33+
"log/std",
34+
"scale-codec/std",
35+
"scale-info/std",
36+
# Substrate
37+
"frame-support/std",
38+
"frame-system/std",
39+
"pallet-timestamp/std",
40+
"sp-runtime/std",
41+
"sp-std/std",
42+
# Frontier
43+
"fp-evm/std",
44+
"pallet-evm/std",
45+
"pallet-evm-system/std",
46+
]
47+
try-runtime = [
48+
"frame-support/try-runtime",
49+
"frame-system/try-runtime",
50+
]
+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//! Account balances logic.
2+
3+
use frame_support::traits::WithdrawReasons;
4+
5+
use super::*;
6+
7+
/// All balance information for an account.
8+
#[derive(Encode, Decode, Clone, PartialEq, Eq, Default, RuntimeDebug, MaxEncodedLen, TypeInfo)]
9+
pub struct AccountData<Balance> {
10+
/// Non-reserved part of the balance. There may still be restrictions on this, but it is the
11+
/// total pool what may in principle be transferred, reserved and used for tipping.
12+
///
13+
/// This is the only balance that matters in terms of most operations on tokens. It
14+
/// alone is used to determine the balance when in the contract execution environment.
15+
pub free: Balance,
16+
}
17+
18+
impl<Balance: Copy> AccountData<Balance> {
19+
/// The total balance in this account.
20+
pub(crate) fn total(&self) -> Balance {
21+
self.free
22+
}
23+
}
24+
25+
/// Simplified reasons for withdrawing balance.
26+
#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, MaxEncodedLen, TypeInfo)]
27+
pub enum Reasons {
28+
/// Paying system transaction fees.
29+
Fee = 0,
30+
/// Any reason other than paying system transaction fees.
31+
Misc = 1,
32+
/// Any reason at all.
33+
All = 2,
34+
}
35+
36+
impl From<WithdrawReasons> for Reasons {
37+
fn from(r: WithdrawReasons) -> Reasons {
38+
if r == WithdrawReasons::TRANSACTION_PAYMENT {
39+
Reasons::Fee
40+
} else if r.contains(WithdrawReasons::TRANSACTION_PAYMENT) {
41+
Reasons::All
42+
} else {
43+
Reasons::Misc
44+
}
45+
}
46+
}

frame/evm-balances/src/imbalances.rs

+172
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
//! Imbalances implementation.
2+
3+
use frame_support::traits::{SameOrOther, TryDrop};
4+
use sp_std::{cmp::Ordering, mem};
5+
6+
use super::*;
7+
8+
/// Opaque, move-only struct with private fields that serves as a token denoting that
9+
/// funds have been created without any equal and opposite accounting.
10+
#[must_use]
11+
#[derive(RuntimeDebug, PartialEq, Eq)]
12+
pub struct PositiveImbalance<T: Config<I>, I: 'static = ()>(T::Balance);
13+
14+
impl<T: Config<I>, I: 'static> PositiveImbalance<T, I> {
15+
/// Create a new positive imbalance from a balance.
16+
pub fn new(amount: T::Balance) -> Self {
17+
PositiveImbalance(amount)
18+
}
19+
}
20+
21+
/// Opaque, move-only struct with private fields that serves as a token denoting that
22+
/// funds have been destroyed without any equal and opposite accounting.
23+
#[must_use]
24+
#[derive(RuntimeDebug, PartialEq, Eq)]
25+
pub struct NegativeImbalance<T: Config<I>, I: 'static = ()>(T::Balance);
26+
27+
impl<T: Config<I>, I: 'static> NegativeImbalance<T, I> {
28+
/// Create a new negative imbalance from a balance.
29+
pub fn new(amount: T::Balance) -> Self {
30+
NegativeImbalance(amount)
31+
}
32+
}
33+
34+
impl<T: Config<I>, I: 'static> TryDrop for PositiveImbalance<T, I> {
35+
fn try_drop(self) -> result::Result<(), Self> {
36+
self.drop_zero()
37+
}
38+
}
39+
40+
impl<T: Config<I>, I: 'static> Default for PositiveImbalance<T, I> {
41+
fn default() -> Self {
42+
Self::zero()
43+
}
44+
}
45+
46+
impl<T: Config<I>, I: 'static> Imbalance<T::Balance> for PositiveImbalance<T, I> {
47+
type Opposite = NegativeImbalance<T, I>;
48+
49+
fn zero() -> Self {
50+
Self(Zero::zero())
51+
}
52+
53+
fn drop_zero(self) -> result::Result<(), Self> {
54+
if self.0.is_zero() {
55+
Ok(())
56+
} else {
57+
Err(self)
58+
}
59+
}
60+
61+
fn split(self, amount: T::Balance) -> (Self, Self) {
62+
let first = self.0.min(amount);
63+
let second = self.0 - first;
64+
65+
mem::forget(self);
66+
(Self(first), Self(second))
67+
}
68+
69+
fn merge(mut self, other: Self) -> Self {
70+
self.0 = self.0.saturating_add(other.0);
71+
mem::forget(other);
72+
73+
self
74+
}
75+
76+
fn subsume(&mut self, other: Self) {
77+
self.0 = self.0.saturating_add(other.0);
78+
mem::forget(other);
79+
}
80+
81+
fn offset(self, other: Self::Opposite) -> SameOrOther<Self, Self::Opposite> {
82+
let (a, b) = (self.0, other.0);
83+
mem::forget((self, other));
84+
85+
match a.cmp(&b) {
86+
Ordering::Greater => SameOrOther::Same(Self(a - b)),
87+
Ordering::Less => SameOrOther::Other(NegativeImbalance::new(b - a)),
88+
Ordering::Equal => SameOrOther::None,
89+
}
90+
}
91+
92+
fn peek(&self) -> T::Balance {
93+
self.0
94+
}
95+
}
96+
97+
impl<T: Config<I>, I: 'static> TryDrop for NegativeImbalance<T, I> {
98+
fn try_drop(self) -> result::Result<(), Self> {
99+
self.drop_zero()
100+
}
101+
}
102+
103+
impl<T: Config<I>, I: 'static> Default for NegativeImbalance<T, I> {
104+
fn default() -> Self {
105+
Self::zero()
106+
}
107+
}
108+
109+
impl<T: Config<I>, I: 'static> Imbalance<T::Balance> for NegativeImbalance<T, I> {
110+
type Opposite = PositiveImbalance<T, I>;
111+
112+
fn zero() -> Self {
113+
Self(Zero::zero())
114+
}
115+
116+
fn drop_zero(self) -> result::Result<(), Self> {
117+
if self.0.is_zero() {
118+
Ok(())
119+
} else {
120+
Err(self)
121+
}
122+
}
123+
124+
fn split(self, amount: T::Balance) -> (Self, Self) {
125+
let first = self.0.min(amount);
126+
let second = self.0 - first;
127+
128+
mem::forget(self);
129+
(Self(first), Self(second))
130+
}
131+
132+
fn merge(mut self, other: Self) -> Self {
133+
self.0 = self.0.saturating_add(other.0);
134+
mem::forget(other);
135+
136+
self
137+
}
138+
139+
fn subsume(&mut self, other: Self) {
140+
self.0 = self.0.saturating_add(other.0);
141+
mem::forget(other);
142+
}
143+
144+
fn offset(self, other: Self::Opposite) -> SameOrOther<Self, Self::Opposite> {
145+
let (a, b) = (self.0, other.0);
146+
mem::forget((self, other));
147+
148+
match a.cmp(&b) {
149+
Ordering::Greater => SameOrOther::Same(Self(a - b)),
150+
Ordering::Less => SameOrOther::Other(PositiveImbalance::new(b - a)),
151+
Ordering::Equal => SameOrOther::None,
152+
}
153+
}
154+
155+
fn peek(&self) -> T::Balance {
156+
self.0
157+
}
158+
}
159+
160+
impl<T: Config<I>, I: 'static> Drop for PositiveImbalance<T, I> {
161+
/// Basic drop handler will just square up the total issuance.
162+
fn drop(&mut self) {
163+
TotalIssuance::<T, I>::mutate(|v| *v = v.saturating_add(self.0));
164+
}
165+
}
166+
167+
impl<T: Config<I>, I: 'static> Drop for NegativeImbalance<T, I> {
168+
/// Basic drop handler will just square up the total issuance.
169+
fn drop(&mut self) {
170+
TotalIssuance::<T, I>::mutate(|v| *v = v.saturating_sub(self.0));
171+
}
172+
}

0 commit comments

Comments
 (0)