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

OrderBook: Add market prices using Oracles #1674

Merged
merged 83 commits into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from 77 commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
1425b3a
Add market price to order book. First impl
lemunozm Jan 5, 2024
dd62147
add reversable market_pair
lemunozm Jan 5, 2024
1880921
add OrderPrice enum
lemunozm Jan 5, 2024
72feba4
change buy_amount to sell_amount
lemunozm Jan 5, 2024
e6e239c
refactor for a cleaner order validation
lemunozm Jan 5, 2024
b4c780c
minor renames and polish
lemunozm Jan 8, 2024
5dafe0e
remove Account from update_order trait. Fix Swap
lemunozm Jan 8, 2024
4fdba6c
remove unused function
lemunozm Jan 8, 2024
d6a250d
extrinsic for setting the feeder
lemunozm Jan 9, 2024
d2362a5
add ratio concept everywhere
lemunozm Jan 10, 2024
9352b94
revert default ratio inverse
lemunozm Jan 10, 2024
b32c25b
fix min_fulfillment_amount after partial fullfill issue. add tests
lemunozm Jan 10, 2024
75daabf
clean mock and refactor some tests
lemunozm Jan 10, 2024
36b4a6d
add more tests
lemunozm Jan 11, 2024
d0ca9dd
finish legacy tests
lemunozm Jan 11, 2024
2789f30
add market tests
lemunozm Jan 11, 2024
3a77f74
refactor benchmarks
lemunozm Jan 12, 2024
86f8259
fix decimal issue with benchmarks and make it generic
lemunozm Jan 12, 2024
840d03d
add weight for the new extrinsic
lemunozm Jan 12, 2024
6f69599
makes foreign-investment to compile (#1687)
lemunozm Jan 12, 2024
8d8d756
add oracle ratio provider and update runtimes
lemunozm Jan 12, 2024
8cb5d5e
minor benchmark renaming
lemunozm Jan 12, 2024
f6c5163
benchmark using market price
lemunozm Jan 12, 2024
93b26e2
fix runtime benchmarks
lemunozm Jan 12, 2024
e939a45
protect againts filling an order with the same account with no balance
lemunozm Jan 12, 2024
6ea8311
fix unitary test compilation for FI
lemunozm Jan 15, 2024
d50a861
add ValueProvider to the pallet to be able to initialize a worst case…
lemunozm Jan 18, 2024
8eb0bdb
remove trait restrictions
lemunozm Jan 18, 2024
5084449
API renames
lemunozm Jan 18, 2024
6d36695
asset to currency
lemunozm Jan 18, 2024
4d8c0c4
removed unused event
lemunozm Jan 18, 2024
19ab933
improve Order ergonomics
lemunozm Jan 18, 2024
632b2ce
minor test change
lemunozm Jan 18, 2024
1445e13
Storing order once
lemunozm Jan 19, 2024
402b145
add RuntimeAPI for min_fulfillment_amount()
lemunozm Jan 19, 2024
c4f3c66
fixes after rebase
lemunozm Jan 28, 2024
438a152
Fix FI to use last orderbook api changes
lemunozm Jan 29, 2024
b0bf18c
add convert_by_market()
lemunozm Jan 29, 2024
2f76dc8
fist approach to adapt FI
lemunozm Jan 29, 2024
635c578
add pending_foreign_amount
lemunozm Jan 29, 2024
3efbed5
finish FI refactor to adapt new orderbook
lemunozm Jan 30, 2024
ff6f63f
revert swap_state for the case of get_order_details
lemunozm Jan 30, 2024
46d3315
swapping tests working
lemunozm Jan 30, 2024
29c0d36
Cargo.lock
lemunozm Jan 30, 2024
32d9096
fix some tests
lemunozm Jan 30, 2024
78ce562
fix decimal issue
lemunozm Jan 30, 2024
ef3de6b
fix all investment tests
lemunozm Jan 30, 2024
188cad3
variable rename
lemunozm Jan 30, 2024
49675d7
all UTs working
lemunozm Jan 30, 2024
b8a990a
update runtimes
lemunozm Jan 30, 2024
4179810
minor simplification
lemunozm Jan 30, 2024
8b44759
variable renaming
lemunozm Jan 30, 2024
b5410fc
more variable renamings
lemunozm Jan 30, 2024
7555cf4
simplification to ease reasoning
lemunozm Jan 30, 2024
b2ce033
fix clippy
lemunozm Jan 30, 2024
99ddf94
Merge remote-tracking branch 'origin/main' into order-book/market-prices
lemunozm Jan 30, 2024
0bff3e8
fix benchmarks
lemunozm Jan 31, 2024
c4fd79c
remove unused benchmark traits
lemunozm Jan 31, 2024
e980cae
add tests for market changes
lemunozm Jan 31, 2024
16633d6
add test to check how the system behaves with decimal precision
lemunozm Jan 31, 2024
305d0df
minor renaming
lemunozm Jan 31, 2024
5c03bd2
allow send Decrease event when increase
lemunozm Jan 31, 2024
9c8751a
fix typos
lemunozm Jan 31, 2024
fe3d679
Simplify a bit pre_increase_swap
lemunozm Jan 31, 2024
92d7b1b
fix foreign typos
lemunozm Jan 31, 2024
b897195
add more readable correlations
lemunozm Feb 1, 2024
2aa4010
divide method in swap & cancel
lemunozm Feb 1, 2024
852c194
simplify pre_increase_swap
lemunozm Feb 1, 2024
15678c9
add minor swap utility
lemunozm Feb 1, 2024
26409c4
fix clippy
lemunozm Feb 1, 2024
5c3fc02
Remove BaseInfo and collect from investment
lemunozm Feb 1, 2024
f899f3b
make pre_decrease_swap more readable
lemunozm Feb 1, 2024
e2e3091
improve correlation docs
lemunozm Feb 1, 2024
1665c3b
fix Decrease when increment issue
lemunozm Feb 1, 2024
5536efe
improve swap test to check swap id storages
lemunozm Feb 2, 2024
9d57e59
remove unused code
lemunozm Feb 2, 2024
8f2ba86
move TooMuchDecrease to its correct place
lemunozm Feb 2, 2024
12d66f6
fix: integration tests for OrderBook market prices (#1717)
wischli Feb 2, 2024
5b597d7
Merge branch 'main' into order-book/market-prices
wischli Feb 2, 2024
217243e
tests: use updated outbound msg sender, not treasury
wischli Feb 2, 2024
9aba062
Merge remote-tracking branch 'origin/main' into order-book/market-prices
lemunozm Feb 2, 2024
4a0f52a
add Feeder event
lemunozm Feb 2, 2024
e579147
remove currency pair storage
lemunozm Feb 2, 2024
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
42 changes: 26 additions & 16 deletions libs/mocks/src/token_swaps.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#[frame_support::pallet]
pub mod pallet {
use cfg_traits::TokenSwaps;
use cfg_traits::{OrderRatio, TokenSwaps};
use frame_support::pallet_prelude::*;
use mock_builder::{execute_call, register_call};

#[pallet::config]
pub trait Config: frame_system::Config {
type CurrencyId;
type Balance;
type SellRatio;
type Ratio;
type OrderId;
type OrderDetails;
}
Expand All @@ -31,17 +31,17 @@ pub mod pallet {
T::CurrencyId,
T::CurrencyId,
T::Balance,
T::SellRatio,
OrderRatio<T::Ratio>,
) -> Result<T::OrderId, DispatchError>
+ 'static,
) {
register_call!(move |(a, b, c, d, e)| f(a, b, c, d, e));
}

pub fn mock_update_order(
f: impl Fn(T::AccountId, T::OrderId, T::Balance, T::SellRatio) -> DispatchResult + 'static,
f: impl Fn(T::OrderId, T::Balance, OrderRatio<T::Ratio>) -> DispatchResult + 'static,
) {
register_call!(move |(a, b, c, d)| f(a, b, c, d));
register_call!(move |(a, b, c)| f(a, b, c));
}

pub fn mock_cancel_order(f: impl Fn(T::OrderId) -> DispatchResult + 'static) {
Expand All @@ -61,48 +61,58 @@ pub mod pallet {
pub fn mock_get_order_details(f: impl Fn(T::OrderId) -> Option<T::OrderDetails> + 'static) {
register_call!(f);
}

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

impl<T: Config> TokenSwaps<T::AccountId> for Pallet<T> {
type Balance = T::Balance;
type CurrencyId = T::CurrencyId;
type OrderDetails = T::OrderDetails;
type OrderId = T::OrderId;
type SellRatio = T::SellRatio;
type Ratio = T::Ratio;

fn place_order(
a: T::AccountId,
b: Self::CurrencyId,
c: Self::CurrencyId,
d: Self::Balance,
e: Self::SellRatio,
e: OrderRatio<Self::Ratio>,
) -> Result<Self::OrderId, DispatchError> {
execute_call!((a, b, c, d, e))
}

fn update_order(
a: T::AccountId,
b: Self::OrderId,
c: Self::Balance,
d: Self::SellRatio,
a: Self::OrderId,
b: Self::Balance,
c: OrderRatio<Self::Ratio>,
) -> DispatchResult {
execute_call!((a, b, c, d))
execute_call!((a, b, c))
}

fn cancel_order(a: Self::OrderId) -> DispatchResult {
execute_call!(a)
}

fn is_active(a: Self::OrderId) -> bool {
execute_call!(a)
}

fn valid_pair(a: Self::CurrencyId, b: Self::CurrencyId) -> bool {
execute_call!((a, b))
}

fn get_order_details(a: Self::OrderId) -> Option<Self::OrderDetails> {
execute_call!(a)
}

fn convert_by_market(
a: Self::CurrencyId,
b: Self::CurrencyId,
c: Self::Balance,
) -> Result<Self::Balance, DispatchError> {
execute_call!((a, b, c))
}
}
}
75 changes: 0 additions & 75 deletions libs/traits/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,81 +52,6 @@ pub trait InvestmentIdBenchmarkHelper {
fn bench_default_investment_id(pool_id: Self::PoolId) -> Self::InvestmentId;
}

/// Benchmark utility for adding currency trading pairs
pub trait OrderBookBenchmarkHelper {
type AccountId;
type Balance;
type CurrencyId;
type OrderIdNonce;

/// Adds the corresponding trading pair, creates trader accounts and mints
/// appropriate amounts of balance into these
fn bench_setup_trading_pair(
asset_in: Self::CurrencyId,
asset_out: Self::CurrencyId,
amount_in: Self::Balance,
amount_out: Self::Balance,
decimals_in: u32,
decimals_out: u32,
) -> (Self::AccountId, Self::AccountId);

/// Fulfills the given swap order from the trader account
fn bench_fill_order_full(trader: Self::AccountId, order_id: Self::OrderIdNonce);
}

/// A representation of information helpful when doing a foreign investment
/// benchmark setup.
pub struct BenchForeignInvestmentSetupInfo<AccountId, InvestmentId, CurrencyId> {
/// The substrate investor address
pub investor: AccountId,
/// The investment id
pub investment_id: InvestmentId,
/// The pool currency which eventually will be invested
pub pool_currency: CurrencyId,
/// The foreign currency which shall be invested and thus swapped into pool
/// currency beforehand
pub foreign_currency: CurrencyId,
/// Bidirectionally funded to fulfill token swap orders
pub funded_trader: AccountId,
}

/// Benchmark utility for updating/collecting foreign investments and
/// redemptions.

pub trait ForeignInvestmentBenchmarkHelper {
type AccountId;
type Balance;
type CurrencyId;
type InvestmentId;

/// Perform necessary setup to enable an investor to invest with or redeem
/// into a foreign currency.
///
/// Returns
/// * The substrate investor address
/// * The investment id
/// * The pool currency id
/// * The foreign currency id
/// * A trading account which can bidirectionally fulfill swap orders for
/// the (foreign, pool) currency pair
fn bench_prepare_foreign_investments_setup(
) -> BenchForeignInvestmentSetupInfo<Self::AccountId, Self::InvestmentId, Self::CurrencyId>;

/// Perform necessary setup to prepare for the worst benchmark case by
/// calling just a single subsequent function.
///
/// NOTE: For the time being, the worst case should be collecting a
/// redemption when there is an active invest swap from foreign to pool. The
/// redemption collection will initiate a swap from pool to foreign such
/// that there is a swap merge conflict to be resolved.
fn bench_prep_foreign_investments_worst_case(
investor: Self::AccountId,
investment_id: Self::InvestmentId,
foreign_currency: Self::CurrencyId,
pool_currency: Self::CurrencyId,
);
}

/// Benchmark utility for adding pool fees
pub trait PoolFeesBenchmarkHelper {
type PoolFeeInfo: Encode + Decode + Clone + TypeInfo + Debug;
Expand Down
102 changes: 22 additions & 80 deletions libs/traits/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -503,98 +503,35 @@ pub trait CurrencyInspect {
fn is_tranche_token(currency: Self::CurrencyId) -> bool;
}

/// Determines an order price
#[derive(Clone, Copy, Debug, Encode, Decode, Eq, PartialEq, MaxEncodedLen, TypeInfo)]
pub enum OrderRatio<Ratio> {
Market,
Custom(Ratio),
}

pub trait TokenSwaps<Account> {
type CurrencyId;
type Balance;
type SellRatio;
type Ratio;
type OrderId;
type OrderDetails;

/// Swap tokens buying a `buy_amount` of `currency_in` using the
/// `currency_out` tokens. The implementer of this method should know
/// the current market rate between those two currencies.
/// `sell_rate_limit` defines the highest price acceptable for
/// `currency_in` currency when buying with `currency_out`. This
/// protects order placer if market changes unfavourably for swap order.
/// For example, with a `sell_rate_limit` of `3/2`, one `asset_in`
/// should never cost more than 1.5 units of `asset_out`. Returns `Result`
/// with `OrderId` upon successful order creation.
///
/// NOTE: The minimum fulfillment amount is implicitly set by the
/// implementor.
///
/// Example usage with `pallet_order_book` impl:
/// ```ignore
/// OrderBook::place_order(
/// {AccountId},
/// CurrencyId::ForeignAsset(0),
/// CurrencyId::ForeignAsset(1),
/// 100 * FOREIGN_ASSET_0_DECIMALS,
/// Quantity::checked_from_rational(3u32, 2u32).unwrap(),
/// 100 * FOREIGN_ASSET_0_DECIMALS
/// )
/// ```
/// Would return `Ok({OrderId}` and create the following order in storage:
/// ```ignore
/// Order {
/// order_id: {OrderId},
/// placing_account: {AccountId},
/// asset_in_id: CurrencyId::ForeignAsset(0),
/// asset_out_id: CurrencyId::ForeignAsset(1),
/// buy_amount: 100 * FOREIGN_ASSET_0_DECIMALS,
/// initial_buy_amount: 100 * FOREIGN_ASSET_0_DECIMALS,
/// sell_rate_limit: Quantity::checked_from_rational(3u32, 2u32).unwrap(),
/// max_sell_amount: 150 * FOREIGN_ASSET_1_DECIMALS,
/// min_fulfillment_amount: 10 * CFG * FOREIGN_ASSET_0_DECIMALS,
/// }
/// ```
/// Swap tokens selling `amount_out` of `currency_out` and buying
/// `currency_in` given an order ratio.
fn place_order(
account: Account,
currency_in: Self::CurrencyId,
currency_out: Self::CurrencyId,
buy_amount: Self::Balance,
sell_rate_limit: Self::SellRatio,
amount_out: Self::Balance,
ratio: OrderRatio<Self::Ratio>,
) -> Result<Self::OrderId, DispatchError>;

/// Update an existing active order.
/// As with creating an order, the `sell_rate_limit` defines the highest
/// price acceptable for `currency_in` currency when buying with
/// `currency_out`. Returns a Dispatch result.
///
/// NOTE: The minimum fulfillment amount is implicitly set by the
/// implementor.
///
/// This Can fail for various reasons.
///
/// Example usage with `pallet_order_book` impl:
/// ```ignore
/// OrderBook::update_order(
/// {AccountId},
/// {OrderId},
/// 15 * FOREIGN_ASSET_0_DECIMALS,
/// Quantity::checked_from_integer(2u32).unwrap(),
/// 6 * FOREIGN_ASSET_0_DECIMALS
/// )
/// ```
/// Would return `Ok(())` and update the following order in storage:
/// ```ignore
/// Order {
/// order_id: {OrderId},
/// placing_account: {AccountId},
/// asset_in_id: CurrencyId::ForeignAsset(0),
/// asset_out_id: CurrencyId::ForeignAsset(1),
/// buy_amount: 15 * FOREIGN_ASSET_0_DECIMALS,
/// initial_buy_amount: 100 * FOREIGN_ASSET_0_DECIMALS,
/// sell_rate_limit: Quantity::checked_from_integer(2u32).unwrap(),
/// max_sell_amount: 30 * FOREIGN_ASSET_1_DECIMALS
/// min_fulfillment_amount: 10 * CFG * FOREIGN_ASSET_0_DECIMALS,
/// }
/// ```
fn update_order(
account: Account,
order_id: Self::OrderId,
buy_amount: Self::Balance,
sell_rate_limit: Self::SellRatio,
amount_out: Self::Balance,
ratio: OrderRatio<Self::Ratio>,
) -> DispatchResult;

/// A sanity check that can be used for validating that a trading pair
Expand All @@ -605,11 +542,16 @@ pub trait TokenSwaps<Account> {
/// Cancel an already active order.
fn cancel_order(order: Self::OrderId) -> DispatchResult;

/// Check if the order is still active.
fn is_active(order: Self::OrderId) -> bool;

/// Retrieve the details of the order if it exists.
fn get_order_details(order: Self::OrderId) -> Option<Self::OrderDetails>;

/// Makes a conversion between 2 currencies using the market ratio between
/// them
fn convert_by_market(
currency_in: Self::CurrencyId,
currency_out: Self::CurrencyId,
amount_out: Self::Balance,
) -> Result<Self::Balance, DispatchError>;
}

/// Trait to transmit a change of status for anything uniquely identifiable.
Expand Down
Loading
Loading