Skip to content

Commit

Permalink
Initial basic implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
dmitrylavrenov committed Aug 7, 2023
1 parent 31c8da1 commit bca632c
Show file tree
Hide file tree
Showing 5 changed files with 473 additions and 0 deletions.
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

0 comments on commit bca632c

Please sign in to comment.