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

FI: Add swapping events #1764

Merged
merged 9 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
13 changes: 13 additions & 0 deletions libs/mocks/src/token_swaps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ pub mod pallet {
register_call!(move |(a, b, c)| f(a, b, c));
}

pub fn mock_market_ratio(
f: impl Fn(T::CurrencyId, T::CurrencyId) -> Result<T::Ratio, DispatchError> + 'static,
) {
register_call!(move |(a, b)| f(a, b));
}

pub fn mock_fill_order(
f: impl Fn(T::AccountId, T::OrderId, T::BalanceOut) -> DispatchResult + 'static,
) {
Expand Down Expand Up @@ -120,6 +126,13 @@ pub mod pallet {
execute_call!((a, b, c))
}

fn market_ratio(
a: Self::CurrencyId,
b: Self::CurrencyId,
) -> Result<Self::Ratio, DispatchError> {
execute_call!((a, b))
}

fn fill_order(a: T::AccountId, b: Self::OrderId, c: Self::BalanceOut) -> DispatchResult {
execute_call!((a, b, c))
}
Expand Down
20 changes: 17 additions & 3 deletions libs/traits/src/swaps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,17 @@ pub trait TokenSwaps<Account> {
currency_out: Self::CurrencyId,
amount_out: Self::BalanceOut,
) -> Result<Self::BalanceIn, DispatchError>;

/// Returns the conversion ratio to convert currency out into currency in,
fn market_ratio(
currency_in: Self::CurrencyId,
currency_out: Self::CurrencyId,
) -> Result<Self::Ratio, DispatchError>;
}

/// A representation of a currency swap in process.
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)]
pub struct SwapState<AmountIn, AmountOut, Currency> {
pub struct SwapInfo<AmountIn, AmountOut, Currency, Ratio> {
/// Swap not yet processed with the pending outcomming amount
pub remaining: Swap<AmountOut, Currency>,

Expand All @@ -112,25 +118,33 @@ pub struct SwapState<AmountIn, AmountOut, Currency> {
/// Amount of incoming currency already swapped denominated in outgoing
/// currency
pub swapped_out: AmountOut,

/// Ratio used to swap `swapped_out` into `swapped_in`
pub ratio: Ratio,
Comment on lines +122 to +123
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The OrderInfo returned by TokenSwaps::get_order_details contains a ratio field of type OrderRatio<Ratio>. Maybe that suffices such that we don't need to introduce an additional ratio field?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OrderRatio is the ratio you want to configure: the way the order behaves. The ratio here is the ratio value itself. It differs, i.e., when OrderRatio::Market, we do not know the ratio value.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation! Makes sense to keep as is then.

}

/// Used as result of `Pallet::apply_swap()`
/// Amounts are donominated referenced by the `new_swap` paramenter given to
/// `apply_swap()`
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct SwapStatus<Amount> {
pub struct SwapStatus<Amount, Ratio> {
/// The incoming amount already swapped and available to use.
pub swapped: Amount,

/// The outgoing amount pending to be swapped
pub pending: Amount,

/// Ratio used to obtain the swapped amount.
/// Zero if no swapped amount.
pub ratio: Ratio,
}

/// Trait to perform swaps without handling directly an order book
pub trait Swaps<AccountId> {
type Amount;
type CurrencyId;
type SwapId;
type Ratio;

/// Apply a swap over a current possible swap state.
/// - If there was no previous swap, it adds it.
Expand All @@ -148,7 +162,7 @@ pub trait Swaps<AccountId> {
who: &AccountId,
swap_id: Self::SwapId,
swap: Swap<Self::Amount, Self::CurrencyId>,
) -> Result<SwapStatus<Self::Amount>, DispatchError>;
) -> Result<SwapStatus<Self::Amount, Self::Ratio>, DispatchError>;

/// Cancel a swap partially or completely. The amount should be expressed in
/// the same currency as the the currency_out of the pending amount.
Expand Down
67 changes: 57 additions & 10 deletions pallets/foreign-investments/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use cfg_traits::{
investments::{ForeignInvestment, Investment, InvestmentCollector},
swaps::{SwapState, Swaps},
swaps::{Swap, SwapInfo, SwapStatus, Swaps},
StatusNotificationHook,
};
use cfg_types::investments::CollectedAmount;
Expand All @@ -12,8 +12,8 @@ use sp_std::marker::PhantomData;

use crate::{
entities::{InvestmentInfo, RedemptionInfo},
pallet::{Config, Error, ForeignInvestmentInfo, ForeignRedemptionInfo, Pallet},
pool_currency_of, Action, SwapId,
pallet::{Config, Error, Event, ForeignInvestmentInfo, ForeignRedemptionInfo, Pallet},
pool_currency_of, Action, SwapId, SwapOf,
};

impl<T: Config> ForeignInvestment<T::AccountId> for Pallet<T> {
Expand Down Expand Up @@ -57,6 +57,8 @@ impl<T: Config> ForeignInvestment<T::AccountId> for Pallet<T> {
}
}

Pallet::<T>::deposit_apply_swap_events(who, swap_id, &swap, &status);

Ok::<_, DispatchError>(msg)
})?;

Expand Down Expand Up @@ -108,6 +110,8 @@ impl<T: Config> ForeignInvestment<T::AccountId> for Pallet<T> {
}
}

Pallet::<T>::deposit_apply_swap_events(who, swap_id, &swap, &status);

if info.is_completed(who, investment_id)? {
*entry = None;
}
Expand Down Expand Up @@ -209,23 +213,64 @@ impl<T: Config> ForeignInvestment<T::AccountId> for Pallet<T> {
}
}

impl<T: Config> Pallet<T> {
fn deposit_apply_swap_events(
who: &T::AccountId,
swap_id: SwapId<T>,
swap: &SwapOf<T>,
status: &SwapStatus<T::SwapBalance, T::SwapRatio>,
) {
if !status.swapped.is_zero() {
Pallet::<T>::deposit_event(Event::SwapFullfilled {
who: who.clone(),
swap_id,
remaining: Swap {
amount_out: status.pending,
..swap.clone()
},
Comment on lines +227 to +230
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that ..swap.clone() contains the currency_in and currency_out to know the swap direction.

swapped_in: status.swapped,
ratio: status.ratio,
});
}

if !status.pending.is_zero() {
Pallet::<T>::deposit_event(Event::SwapCreated {
who: who.clone(),
swap_id,
swap: Swap {
amount_out: status.pending,
..swap.clone()
},
})
}
}
}

pub struct FulfilledSwapHook<T>(PhantomData<T>);
impl<T: Config> StatusNotificationHook for FulfilledSwapHook<T> {
type Error = DispatchError;
type Id = (T::AccountId, SwapId<T>);
type Status = SwapState<T::SwapBalance, T::SwapBalance, T::CurrencyId>;
type Status = SwapInfo<T::SwapBalance, T::SwapBalance, T::CurrencyId, T::SwapRatio>;

fn notify_status_change(
(who, (investment_id, action)): Self::Id,
swap_state: Self::Status,
swap_info: Self::Status,
) -> DispatchResult {
let pool_currency = pool_currency_of::<T>(investment_id)?;
let swapped_amount_in = swap_state.swapped_in;
let swapped_amount_out = swap_state.swapped_out;
let pending_amount = swap_state.remaining.amount_out;
let swapped_amount_in = swap_info.swapped_in;
let swapped_amount_out = swap_info.swapped_out;
let pending_amount = swap_info.remaining.amount_out;

Pallet::<T>::deposit_event(Event::SwapFullfilled {
who: who.clone(),
swap_id: (investment_id, action),
remaining: swap_info.remaining.clone(),
swapped_in: swap_info.swapped_in,
ratio: swap_info.ratio,
});

match action {
Action::Investment => match pool_currency == swap_state.remaining.currency_in {
Action::Investment => match pool_currency == swap_info.remaining.currency_in {
true => SwapDone::<T>::for_increase_investment(
&who,
investment_id,
Expand Down Expand Up @@ -308,7 +353,9 @@ impl<T: Config> StatusNotificationHook for CollectedRedemptionHook<T> {

if let Some(swap) = swap {
let swap_id = (investment_id, Action::Redemption);
let status = T::Swaps::apply_swap(&who, swap_id, swap)?;
let status = T::Swaps::apply_swap(&who, swap_id, swap.clone())?;

Pallet::<T>::deposit_apply_swap_events(&who, swap_id, &swap, &status);

if !status.swapped.is_zero() {
SwapDone::<T>::for_redemption(
Expand Down
23 changes: 23 additions & 0 deletions pallets/foreign-investments/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ pub mod pallet {
/// depends.
#[pallet::config]
pub trait Config: frame_system::Config {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;

/// Represents a foreign amount
type ForeignBalance: Parameter
+ Member
Expand Down Expand Up @@ -149,6 +151,9 @@ pub mod pallet {
/// Any balances used in TokenSwaps
type SwapBalance: Parameter + Member + AtLeast32BitUnsigned + Default + Copy + MaxEncodedLen;

/// Ratio used for swapping amounts
type SwapRatio: Parameter + Member + Copy + MaxEncodedLen;

/// The currency type of transferrable tokens
type CurrencyId: Parameter + Member + Copy + MaxEncodedLen;

Expand Down Expand Up @@ -181,6 +186,7 @@ pub mod pallet {
CurrencyId = Self::CurrencyId,
Amount = Self::SwapBalance,
SwapId = SwapId<Self>,
Ratio = Self::SwapRatio,
>;

/// The hook type which acts upon a finalized investment decrement.
Expand Down Expand Up @@ -263,4 +269,21 @@ pub mod pallet {
/// The decrease is greater than the current investment/redemption
TooMuchDecrease,
}

#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
SwapCreated {
who: T::AccountId,
swap_id: SwapId<T>,
swap: SwapOf<T>,
},
SwapFullfilled {
who: T::AccountId,
swap_id: SwapId<T>,
remaining: SwapOf<T>,
swapped_in: T::SwapBalance,
ratio: T::SwapRatio,
},
}
}
3 changes: 3 additions & 0 deletions pallets/foreign-investments/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ impl pallet_swaps::Config for Runtime {
type FulfilledSwap = FulfilledSwapHook<Runtime>;
type OrderBook = MockTokenSwaps;
type OrderId = OrderId;
type Ratio = Ratio;
type SwapId = SwapId<Runtime>;
}

Expand All @@ -148,7 +149,9 @@ impl pallet_foreign_investments::Config for Runtime {
type InvestmentId = InvestmentId;
type PoolBalance = Balance;
type PoolInspect = MockPools;
type RuntimeEvent = RuntimeEvent;
type SwapBalance = Balance;
type SwapRatio = Ratio;
type Swaps = Swaps;
type TrancheBalance = Balance;
}
Expand Down
16 changes: 14 additions & 2 deletions pallets/foreign-investments/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use cfg_traits::{
investments::{ForeignInvestment as _, Investment, TrancheCurrency},
swaps::{OrderInfo, OrderRatio, Swap, SwapState, TokenSwaps},
swaps::{OrderInfo, OrderRatio, Swap, SwapInfo, TokenSwaps},
StatusNotificationHook,
};
use cfg_types::investments::{
CollectedAmount, ExecutedForeignCollect, ExecutedForeignDecreaseInvest,
};
use frame_support::{assert_err, assert_ok};
use sp_runtime::traits::One;
use sp_std::sync::{Arc, Mutex};

use crate::{
Expand Down Expand Up @@ -57,6 +58,14 @@ mod util {
}
}

pub fn market_ratio(to: CurrencyId, from: CurrencyId) -> Ratio {
match (from, to) {
(POOL_CURR, FOREIGN_CURR) => Ratio::from_rational(1, STABLE_RATIO),
(FOREIGN_CURR, POOL_CURR) => Ratio::from_rational(STABLE_RATIO, 1),
_ => Ratio::one(),
}
}

pub fn configure_pool() {
MockPools::mock_currency_for(|pool_id| {
assert_eq!(pool_id, INVESTMENT_ID.of_pool());
Expand Down Expand Up @@ -105,6 +114,8 @@ mod util {
MockTokenSwaps::mock_convert_by_market(|to, from, amount_from| {
Ok(convert_currencies(to, from, amount_from))
});

MockTokenSwaps::mock_market_ratio(|to, from| Ok(util::market_ratio(to, from)));
}

// Setup basic investment system
Expand Down Expand Up @@ -146,7 +157,7 @@ mod util {

Swaps::notify_status_change(
order_id,
SwapState {
SwapInfo {
remaining: Swap {
amount_out: order.swap.amount_out - amount_out,
..order.swap
Expand All @@ -158,6 +169,7 @@ mod util {
)
.unwrap(),
swapped_out: amount_out,
ratio: util::market_ratio(order.swap.currency_in, order.swap.currency_out),
},
)
.unwrap();
Expand Down
14 changes: 11 additions & 3 deletions pallets/order-book/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub use weights::WeightInfo;
pub mod pallet {
use cfg_primitives::conversion::convert_balance_decimals;
use cfg_traits::{
swaps::{OrderInfo, OrderRatio, Swap, SwapState, TokenSwaps},
swaps::{OrderInfo, OrderRatio, Swap, SwapInfo, TokenSwaps},
ConversionToAssetBalance, StatusNotificationHook, ValueProvider,
};
use cfg_types::{self, tokens::CustomMetadata};
Expand Down Expand Up @@ -170,7 +170,7 @@ pub mod pallet {
/// The hook which acts upon a (partially) fulfilled order
type FulfilledOrderHook: StatusNotificationHook<
Id = Self::OrderIdNonce,
Status = SwapState<Self::BalanceIn, Self::BalanceOut, Self::CurrencyId>,
Status = SwapInfo<Self::BalanceIn, Self::BalanceOut, Self::CurrencyId, Self::Ratio>,
Error = DispatchError,
>;

Expand Down Expand Up @@ -613,14 +613,15 @@ pub mod pallet {

T::FulfilledOrderHook::notify_status_change(
order.order_id,
SwapState {
SwapInfo {
remaining: Swap {
amount_out: remaining_amount_out,
currency_in: order.currency_in,
currency_out: order.currency_out,
},
swapped_in: amount_in,
swapped_out: amount_out,
ratio,
},
)?;

Expand Down Expand Up @@ -768,6 +769,13 @@ pub mod pallet {
let ratio = Self::market_ratio(currency_out, currency_in)?;
Self::convert_with_ratio(currency_out, currency_in, ratio, amount_out)
}

fn market_ratio(
currency_in: Self::CurrencyId,
currency_out: Self::CurrencyId,
) -> Result<Self::Ratio, DispatchError> {
Self::market_ratio(currency_out, currency_in)
}
}

#[cfg(feature = "runtime-benchmarks")]
Expand Down
4 changes: 2 additions & 2 deletions pallets/order-book/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// GNU General Public License for more details.

use cfg_mocks::pallet_mock_fees;
use cfg_traits::{swaps::SwapState, ConversionToAssetBalance};
use cfg_traits::{swaps::SwapInfo, ConversionToAssetBalance};
use cfg_types::tokens::{CurrencyId, CustomMetadata};
use frame_support::{
parameter_types,
Expand Down Expand Up @@ -125,7 +125,7 @@ impl cfg_mocks::fees::pallet::Config for Runtime {

impl cfg_mocks::status_notification::pallet::Config for Runtime {
type Id = OrderId;
type Status = SwapState<Balance, Balance, CurrencyId>;
type Status = SwapInfo<Balance, Balance, CurrencyId, Ratio>;
}

parameter_types! {
Expand Down
Loading
Loading