diff --git a/Cargo.lock b/Cargo.lock index 7cbe180bf..2ec96fc9d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -776,6 +776,14 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" +[[package]] +name = "bridge-pot-currency-swap" +version = "0.1.0" +dependencies = [ + "frame-support", + "primitives-currency-swap", +] + [[package]] name = "bs58" version = "0.4.0" diff --git a/crates/bridge-pot-currency-swap/Cargo.toml b/crates/bridge-pot-currency-swap/Cargo.toml new file mode 100644 index 000000000..e02df5338 --- /dev/null +++ b/crates/bridge-pot-currency-swap/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "bridge-pot-currency-swap" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +primitives-currency-swap = { version = "0.1", path = "../primitives-currency-swap", default-features = false } + +frame-support = { default-features = false, git = "https://github.com/humanode-network/substrate", branch = "locked/polkadot-v0.9.38" } + +[features] +default = ["std"] +std = ["frame-support/std", "primitives-currency-swap/std"] +try-runtime = ["frame-support/try-runtime", "primitives-currency-swap/try-runtime"] diff --git a/crates/bridge-pot-currency-swap/src/existence_optional.rs b/crates/bridge-pot-currency-swap/src/existence_optional.rs new file mode 100644 index 000000000..27db74dcf --- /dev/null +++ b/crates/bridge-pot-currency-swap/src/existence_optional.rs @@ -0,0 +1,37 @@ +//! An implementation that does not require pot account existence and can potentially kill the +//! pot account by withdrawing all the funds from it. + +use frame_support::{ + sp_runtime::{traits::Convert, DispatchError}, + traits::{Currency, ExistenceRequirement, Get, Imbalance, WithdrawReasons}, +}; + +use super::{Config, CurrencySwap}; + +/// A marker type for the implementation that does not require pot accounts existence. +pub enum Marker {} + +impl primitives_currency_swap::CurrencySwap + for CurrencySwap +{ + type From = T::CurrencyFrom; + type To = T::CurrencyTo; + type Error = DispatchError; + + fn swap( + imbalance: >::NegativeImbalance, + ) -> Result<>::NegativeImbalance, Self::Error> { + let amount = imbalance.peek(); + + T::CurrencyFrom::resolve_creating(&T::PotFrom::get(), imbalance); + + let imbalance = T::CurrencyTo::withdraw( + &T::PotTo::get(), + T::BalanceCoverter::convert(amount), + WithdrawReasons::TRANSFER, + ExistenceRequirement::AllowDeath, + )?; + + Ok(imbalance) + } +} diff --git a/crates/bridge-pot-currency-swap/src/existence_required.rs b/crates/bridge-pot-currency-swap/src/existence_required.rs new file mode 100644 index 000000000..12a954508 --- /dev/null +++ b/crates/bridge-pot-currency-swap/src/existence_required.rs @@ -0,0 +1,57 @@ +//! An implementation that requires and ensures pot account existence. + +use frame_support::{ + sp_runtime::{traits::Convert, DispatchError}, + traits::{Currency, ExistenceRequirement, Get, Imbalance, WithdrawReasons}, +}; + +use super::{Config, CurrencySwap}; + +/// A marker type for the implementation that requires pot accounts existence. +pub enum Marker {} + +/// An error that can occur while doing the swap operation. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Error { + /// Unable to resolve the incoming balance into the corresponding pot. + ResolvingIncomingImbalance(ImbalanceFrom), + /// Unable to withdraw the outgoing balance from the corresponding pot. + IssuingOutgoingImbalance(DispatchError), +} + +impl From> for DispatchError { + fn from(value: Error) -> Self { + match value { + Error::ResolvingIncomingImbalance(_) => DispatchError::NoProviders, + Error::IssuingOutgoingImbalance(err) => err, + } + } +} + +impl primitives_currency_swap::CurrencySwap + for CurrencySwap +{ + type From = T::CurrencyFrom; + type To = T::CurrencyTo; + type Error = + Error<<::CurrencyFrom as Currency>::NegativeImbalance>; + + fn swap( + imbalance: >::NegativeImbalance, + ) -> Result<>::NegativeImbalance, Self::Error> { + let amount = imbalance.peek(); + + T::CurrencyFrom::resolve_into_existing(&T::PotFrom::get(), imbalance) + .map_err(Error::ResolvingIncomingImbalance)?; + + let imbalance = T::CurrencyTo::withdraw( + &T::PotTo::get(), + T::BalanceCoverter::convert(amount), + WithdrawReasons::TRANSFER, + ExistenceRequirement::KeepAlive, + ) + .map_err(Error::IssuingOutgoingImbalance)?; + + Ok(imbalance) + } +} diff --git a/crates/bridge-pot-currency-swap/src/lib.rs b/crates/bridge-pot-currency-swap/src/lib.rs new file mode 100644 index 000000000..36132faea --- /dev/null +++ b/crates/bridge-pot-currency-swap/src/lib.rs @@ -0,0 +1,48 @@ +//! Bridge pot currency swap 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::Convert, + sp_std::marker::PhantomData, + traits::{Currency, Get}, +}; + +pub mod existence_optional; +pub mod existence_required; + +pub use existence_optional::Marker as ExistenceOptional; +pub use existence_required::Marker as ExistenceRequired; + +/// The config for the generic bridge pot currency swap logic. +pub trait Config { + /// The type representing the account key for the currency to swap from. + type AccountIdFrom; + + /// The type representing the account key for the currency to swap to. + type AccountIdTo; + + /// The currency to swap from. + type CurrencyFrom: Currency; + + /// The currency to swap to. + type CurrencyTo: Currency; + + /// The converter to determine how the balance amount should be converted from one currency to + /// another. + type BalanceCoverter: Convert< + >::Balance, + >::Balance, + >; + + /// The account to land the balances to when receiving the funds as part of the swap operation. + type PotFrom: Get; + + /// The account to take the balances from when sending the funds as part of the swap operation. + type PotTo: Get; +} + +/// A [`primitives_currency_swap::CurrencySwap`] implementation that does the swap using two +/// "pot" accounts for each of end swapped currencies. +pub struct CurrencySwap(PhantomData<(T, ExistenceRequirement)>);