Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
bca632c
Initial basic implementation
dmitrylavrenov Aug 7, 2023
8c0c96b
Inline implementations
dmitrylavrenov Aug 8, 2023
14e2bf0
Docs and refactoring
dmitrylavrenov Aug 8, 2023
a71541e
Handle all bridges initial balances cases
dmitrylavrenov Aug 8, 2023
a976d20
Fix basic test
dmitrylavrenov Aug 8, 2023
6a09b50
Properly handle edge cases
dmitrylavrenov Aug 8, 2023
33f6956
Improve tests
dmitrylavrenov Aug 8, 2023
96102f3
Add initialization_fails_treasury_insufficient_balance test
dmitrylavrenov Aug 8, 2023
b7f58c0
Update features snapshot
dmitrylavrenov Aug 8, 2023
8c25bf4
Add weight value calculation
dmitrylavrenov Aug 8, 2023
71c3178
Add runtime-upgrade logic
dmitrylavrenov Aug 8, 2023
2d04e2a
Add runtime upgrade test
dmitrylavrenov Aug 9, 2023
a80bb29
Check is balanced before applying initialization
dmitrylavrenov Aug 9, 2023
00cf8fc
Fix try-runtime feature related code
dmitrylavrenov Aug 9, 2023
1ad8152
Rename pallet in mock
dmitrylavrenov Aug 9, 2023
55ad986
Use runtime_lock and externalities logic as shared components
dmitrylavrenov Aug 9, 2023
421ef86
More explicit mocks usage in tests
dmitrylavrenov Aug 9, 2023
28836f8
Use a struct type for address/balance pair in tests
dmitrylavrenov Aug 9, 2023
0dcc6c4
Rename version mocks
dmitrylavrenov Aug 9, 2023
d374d66
Add initialization idempotence test
dmitrylavrenov Aug 9, 2023
b2d8d28
Add initializer version storage
dmitrylavrenov Aug 9, 2023
2a2617a
Add verify_balanced call
dmitrylavrenov Aug 9, 2023
7e04f1c
Merge branch 'master' into pallet-bridges-init-currency-swap
dmitrylavrenov Aug 9, 2023
bc502f9
Edit docs
dmitrylavrenov Aug 10, 2023
c55b011
Twice immediate reinvocation idempotency
dmitrylavrenov Aug 10, 2023
55a9f83
Add transfer with creating account to test
dmitrylavrenov Aug 10, 2023
f1b4304
Make is_balanced fn public
dmitrylavrenov Aug 10, 2023
5ef7ed1
Fix typos
dmitrylavrenov Aug 11, 2023
7bacc72
Improve docs and debug_assert for make_native_bridge_balance_be
dmitrylavrenov Aug 11, 2023
d10ea31
Improve docs and debug_assert for make_evm_bridge_balance_be
dmitrylavrenov Aug 11, 2023
4f28682
Improve assert messages
dmitrylavrenov Aug 11, 2023
a5876ad
Proportionally equal natve and evm total issuances
dmitrylavrenov Aug 14, 2023
63a5a27
Fix is_balanced logic to calculate different swappable balances
dmitrylavrenov Aug 14, 2023
43fc65c
Rename pallet
dmitrylavrenov Aug 15, 2023
5075aea
Use a helper function to calculate required bridges minimum balances
dmitrylavrenov Aug 15, 2023
a226350
Fix pallet renaming in tests
dmitrylavrenov Aug 15, 2023
682cb95
Fix pallet renaming in features snapshot
dmitrylavrenov Aug 15, 2023
dc3ae88
Merge branch 'master' into pallet-bridges-init-currency-swap
dmitrylavrenov Aug 15, 2023
7c7f031
Return test
dmitrylavrenov Aug 15, 2023
53dde76
Add docs for tests
dmitrylavrenov Aug 15, 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
14 changes: 14 additions & 0 deletions Cargo.lock

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

36 changes: 36 additions & 0 deletions crates/pallet-bridges-initializer-currency-swap/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[package]
name = "pallet-bridges-initializer-currency-swap"
version = "0.1.0"
edition = "2021"
publish = false

[dependencies]
codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] }
frame-support = { default-features = false, git = "https://github.com/humanode-network/substrate", branch = "locked/polkadot-v0.9.38" }
frame-system = { default-features = false, git = "https://github.com/humanode-network/substrate", branch = "locked/polkadot-v0.9.38" }
scale-info = { version = "2.5.0", default-features = false, features = ["derive"] }
sp-std = { default-features = false, git = "https://github.com/humanode-network/substrate", branch = "locked/polkadot-v0.9.38" }

[dev-dependencies]
pallet-pot = { version = "0.1", path = "../pallet-pot", default-features = false }

pallet-balances = { git = "https://github.com/humanode-network/substrate", branch = "locked/polkadot-v0.9.38" }
sp-core = { git = "https://github.com/humanode-network/substrate", branch = "locked/polkadot-v0.9.38" }

[features]
default = ["std"]
std = [
"codec/std",
"frame-support/std",
"frame-system/std",
"pallet-balances/std",
"pallet-pot/std",
"scale-info/std",
"sp-std/std",
]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
"pallet-balances/try-runtime",
"pallet-pot/try-runtime",
]
182 changes: 182 additions & 0 deletions crates/pallet-bridges-initializer-currency-swap/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
//! A substrate pallet for bridge pot currency swap initialization implementation.

// Either generate code at stadard mode, or `no_std`, based on the `std` feature presence.
#![cfg_attr(not(feature = "std"), no_std)]

use frame_support::{
sp_runtime::{
traits::{CheckedAdd, CheckedSub, Convert, Get},
ArithmeticError, DispatchError,
},
traits::{fungible, Currency},
};
pub use pallet::*;

#[cfg(test)]
mod mock;

#[cfg(test)]
mod tests;

pub trait BalanceMaker<AccountId, C: Currency<AccountId>> {
const IS_SWAPPABLE_CHANGED: bool;

fn make_balance(amount: C::Balance) -> Result<(), DispatchError>;
}

// We have to temporarily allow some clippy lints. Later on we'll send patches to substrate to
// fix them at their end.
#[allow(clippy::missing_docs_in_private_items)]
#[frame_support::pallet]
pub mod pallet {
use frame_support::{pallet_prelude::*, sp_runtime::traits::MaybeDisplay};
use sp_std::fmt::Debug;

use super::*;

/// The Bridge Pot Currency Swap Pallet.
#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T>(_);

/// Configuration trait of this pallet.
#[pallet::config]
pub trait Config: frame_system::Config {
type EvmAccountId: Parameter
+ Member
+ MaybeSerializeDeserialize
+ Debug
+ MaybeDisplay
+ Ord
+ MaxEncodedLen;

type NativeCurrency: Currency<Self::AccountId>
+ fungible::Inspect<
Self::AccountId,
Balance = <Self::NativeCurrency as Currency<Self::AccountId>>::Balance,
>;

type EvmCurrency: Currency<Self::EvmAccountId>
+ fungible::Inspect<
Self::EvmAccountId,
Balance = <Self::EvmCurrency as Currency<Self::EvmAccountId>>::Balance,
>;

type BalanceConverterNativeToEvm: Convert<
<Self::NativeCurrency as Currency<Self::AccountId>>::Balance,
<Self::EvmCurrency as Currency<Self::EvmAccountId>>::Balance,
>;

type BalanceConverterEvmToNative: Convert<
<Self::EvmCurrency as Currency<Self::EvmAccountId>>::Balance,
<Self::NativeCurrency as Currency<Self::AccountId>>::Balance,
>;

type NativeEvmBridgePot: Get<Self::AccountId>;
type NativeBridgeBalanceMaker: BalanceMaker<Self::AccountId, Self::NativeCurrency>;

type EvmNativeBridgePot: Get<Self::EvmAccountId>;
type EvmBridgeBalanceMaker: BalanceMaker<Self::EvmAccountId, Self::EvmCurrency>;
}

#[pallet::genesis_config]
pub struct GenesisConfig<T: Config>(PhantomData<T>);

// The default value for the genesis config type.
#[cfg(feature = "std")]
impl<T: Config> Default for GenesisConfig<T> {
fn default() -> Self {
Self(PhantomData)
}
}

// The build of genesis for the pallet.
#[pallet::genesis_build]
impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
fn build(&self) {
match Pallet::<T>::init() {
Ok(_) => {}
Err(err) => panic!("error during bridges initialization: {err:?}",),
}
}
}
}

impl<T: Config> Pallet<T> {
pub fn init() -> Result<(), DispatchError> {
assert!(
!T::EvmBridgeBalanceMaker::IS_SWAPPABLE_CHANGED,
"not supported"
);

let evm_total_issuance = T::EvmCurrency::total_issuance();
let evm_swappable = evm_total_issuance;

let native_swap_reserved = T::BalanceConverterEvmToNative::convert(evm_swappable);
let native_bridge_balance = native_swap_reserved
.checked_add(&T::NativeCurrency::minimum_balance())
.ok_or(ArithmeticError::Overflow)?;

T::NativeBridgeBalanceMaker::make_balance(native_bridge_balance)?;

let native_total_issuance = T::NativeCurrency::total_issuance();
let native_swappable = native_total_issuance
.checked_sub(&native_bridge_balance)
.ok_or(ArithmeticError::Underflow)?;

let evm_swap_reserved = T::BalanceConverterNativeToEvm::convert(native_swappable);
let evm_bridge_balance = evm_swap_reserved
.checked_add(&T::EvmCurrency::minimum_balance())
.ok_or(ArithmeticError::Overflow)?;

T::EvmBridgeBalanceMaker::make_balance(evm_bridge_balance)?;

assert!(Self::verify_balanced()?, "not balanced");

Ok(())
}

fn verify_balanced() -> Result<bool, ArithmeticError> {
let is_balanced_native_evm = swap_reserved_balance::<
T::AccountId,
T::NativeCurrency,
T::NativeEvmBridgePot,
>()? == T::BalanceConverterEvmToNative::convert(
swappable_balance::<T::EvmAccountId, T::EvmCurrency, T::EvmNativeBridgePot>()?,
);

let is_balanced_evm_native =
T::BalanceConverterNativeToEvm::convert(swap_reserved_balance::<
T::AccountId,
T::NativeCurrency,
T::NativeEvmBridgePot,
>()?)
== swappable_balance::<T::EvmAccountId, T::EvmCurrency, T::EvmNativeBridgePot>()?;

Ok(is_balanced_native_evm && is_balanced_evm_native)
}
}

/// Swappable balance.
fn swappable_balance<AccountId, C: Currency<AccountId>, B: Get<AccountId>>(
) -> Result<C::Balance, ArithmeticError> {
let total = C::total_issuance();
let bridge = C::total_balance(&B::get());

let swappable = total
.checked_sub(&bridge)
.ok_or(ArithmeticError::Underflow)?;

Ok(swappable)
}

/// Swap reserved balance.
fn swap_reserved_balance<AccountId, C: Currency<AccountId>, B: Get<AccountId>>(
) -> Result<C::Balance, ArithmeticError> {
let bridge = C::total_balance(&B::get());
let ed = C::minimum_balance();

let reserved = bridge.checked_sub(&ed).ok_or(ArithmeticError::Underflow)?;

Ok(reserved)
}
Loading