From bb29f86fe288842706be6516bf8d36d91cfad572 Mon Sep 17 00:00:00 2001 From: delaaxe <1091900+delaaxe@users.noreply.github.com> Date: Mon, 25 Sep 2023 20:02:19 +0300 Subject: [PATCH] Feat: Implement the functions in the `swap_pricing_utils` library (#446) * Add swap pricing utils wip * Add pricing utils * use i128 * Fix i128 * Use i128 * Fix swap fees * Remove duplicated functions * Add tests * Fixes * Cleanup * Update market_utils.cairo * Review comments * Rename i128 functions * Rename I128Store * Add test * Format --- src/event/event_emitter.cairo | 4 +- src/lib.cairo | 6 +- src/market/market_utils.cairo | 73 ++++-- src/order/base_order_utils.cairo | 11 +- src/position/position_utils.cairo | 44 ++-- src/pricing/error.cairo | 3 + src/pricing/position_pricing_utils.cairo | 2 +- src/pricing/pricing_utils.cairo | 2 +- src/pricing/swap_pricing_utils.cairo | 228 +++++++++++++++--- src/reader/reader.cairo | 4 +- src/reader/reader_pricing_utils.cairo | 21 +- src/reader/reader_utils.cairo | 2 +- src/swap/error.cairo | 4 +- src/swap/swap_handler.cairo | 1 + src/swap/swap_utils.cairo | 30 +-- .../event/test_position_events_emitted.cairo | 2 +- .../pricing/test_swap_pricing_utils.cairo | 131 ++++++++++ src/tests/utils/test_i128.cairo | 2 +- src/token/token_utils.cairo | 2 +- src/utils/calc.cairo | 19 +- src/utils/i128.cairo | 31 +-- src/utils/test_pricing_utils.cairo | 8 +- 22 files changed, 484 insertions(+), 146 deletions(-) create mode 100644 src/pricing/error.cairo create mode 100644 src/tests/pricing/test_swap_pricing_utils.cairo diff --git a/src/event/event_emitter.cairo b/src/event/event_emitter.cairo index fbfe22818..185321c53 100644 --- a/src/event/event_emitter.cairo +++ b/src/event/event_emitter.cairo @@ -19,7 +19,7 @@ use satoru::price::price::Price; use satoru::pricing::position_pricing_utils::PositionFees; use satoru::order::order::{Order, SecondaryOrderType}; use satoru::utils::span32::{Span32, DefaultSpan32}; -use satoru::utils::i128::{I128Div, I128Mul, I128Serde}; +use satoru::utils::i128::{I128Div, I128Mul, I128Store, I128Serde}; //TODO: OrderCollatDeltaAmountAutoUpdtd must be renamed back to OrderCollateralDeltaAmountAutoUpdated when string will be allowed as event argument @@ -672,7 +672,7 @@ mod EventEmitter { use satoru::pricing::position_pricing_utils::PositionFees; use satoru::order::order::{Order, SecondaryOrderType}; use satoru::utils::span32::{Span32, DefaultSpan32}; - use satoru::utils::i128::{I128Div, I128Mul, I128Serde}; + use satoru::utils::i128::{I128Div, I128Mul, I128Store, I128Serde}; // ************************************************************************* // STORAGE diff --git a/src/lib.cairo b/src/lib.cairo index 7fdf19d31..e9696c19d 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -215,6 +215,7 @@ mod pricing { mod position_pricing_utils; mod pricing_utils; mod swap_pricing_utils; + mod error; } // `referral` contains referral logic. @@ -312,11 +313,12 @@ mod tests { mod price { mod test_price; } - + mod pricing { + mod test_swap_pricing_utils; + } mod reader { mod test_reader; } - mod role { mod test_role_module; mod test_role_store; diff --git a/src/market/market_utils.cairo b/src/market/market_utils.cairo index 1174848fe..8e160d42d 100644 --- a/src/market/market_utils.cairo +++ b/src/market/market_utils.cairo @@ -19,8 +19,10 @@ use satoru::market::{ }; use satoru::oracle::oracle::{IOracleDispatcher, IOracleDispatcherTrait}; use satoru::price::price::{Price, PriceTrait}; +use satoru::utils::calc; use satoru::utils::span32::Span32; -use satoru::utils::i128::{StoreI128, u128_to_i128, I128Serde, I128Div, I128Mul}; +use satoru::utils::i128::{I128Store, I128Serde, I128Div, I128Mul, I128Default}; + /// Struct to store the prices of tokens of a market. /// # Params /// * `indexTokenPrice` - Price of the market's index token. @@ -73,11 +75,11 @@ fn get_cached_token_price(token: ContractAddress, market: Market, prices: Market } fn get_swap_impact_amount_with_cap( - dataStore: IDataStoreDispatcher, + data_store: IDataStoreDispatcher, market: ContractAddress, token: ContractAddress, - tokenPrice: Price, - priceImpactUsd: i128 //TODO : check u128 + token_price: Price, + price_impact_usd: i128 //TODO : check u128 ) -> i128 { //Todo : check u128 //TODO return 0; @@ -338,8 +340,8 @@ fn get_pnl( maximize: bool ) -> i128 { // Get the open interest. - let open_interest = u128_to_i128( - get_open_interest_for_market_is_long(data_store, market, is_long) + let open_interest = calc::to_signed( + get_open_interest_for_market_is_long(data_store, market, is_long), true ); // Get the open interest in tokens. let open_interest_in_tokens = get_open_interest_in_tokens_for_market( @@ -354,7 +356,7 @@ fn get_pnl( let price = index_token_price.pick_price_for_pnl(is_long, maximize); // `open_interest` is the cost of all positions, `open_interest_valu`e is the current worth of all positions. - let open_interest_value = u128_to_i128(open_interest_in_tokens * price); + let open_interest_value = calc::to_signed(open_interest_in_tokens * price, true); // Return the PNL. // If `is_long` is true, then the PNL is the difference between the current worth of all positions and the cost of all positions. @@ -694,6 +696,16 @@ fn is_pnl_factor_exceeded_direct( (true, 0, 0) } +fn get_ui_fee_factor(data_store: IDataStoreDispatcher, account: ContractAddress) -> u128 { + let max_ui_fee_factor = data_store.get_u128(keys::max_ui_fee_factor()); + let ui_fee_factor = data_store.get_u128(keys::ui_fee_factor_key(account)); + if ui_fee_factor < max_ui_fee_factor { + ui_fee_factor + } else { + max_ui_fee_factor + } +} + /// Gets the enabled market. This function will revert if the market does not exist or is not enabled. /// # Arguments /// * `dataStore` - DataStore @@ -961,7 +973,6 @@ fn market_token_amount_to_usd( 0 } - /// Get the borrowing factor per second. /// # Arguments /// * `data_store` - The data store to use. @@ -1039,18 +1050,52 @@ fn get_open_interest_with_pnl( 0 } - /// Get the virtual inventory for swaps /// # Arguments /// * `data_store` - The data store to use. -/// * `market` - The market address. +/// * `market` - The market. /// # Returns -/// has virtual inventory, virtual long token inventory, virtual short token inventory +/// The tuple (has virtual inventory, virtual long token inventory, virtual short token inventory) fn get_virtual_inventory_for_swaps( - data_store: IDataStoreDispatcher, market: ContractAddress, + data_store: IDataStoreDispatcher, market: ContractAddress ) -> (bool, u128, u128) { - // TODO - (false, 0, 0) + let virtual_market_id = data_store.get_felt252(keys::virtual_market_id_key(market)); + if virtual_market_id.is_zero() { + return (false, 0, 0); + } + + return ( + true, + data_store.get_u128(keys::virtual_inventory_for_swaps_key(virtual_market_id, true)), + data_store.get_u128(keys::virtual_inventory_for_swaps_key(virtual_market_id, false)) + ); +} + +fn get_adjusted_swap_impact_factor( + data_store: IDataStoreDispatcher, market: ContractAddress, is_positive: bool +) -> u128 { + let (positive_impact_factor, negative_impact_factor) = get_adjusted_swap_impact_factors( + data_store, market + ); + if is_positive { + positive_impact_factor + } else { + negative_impact_factor + } +} + +fn get_adjusted_swap_impact_factors( + data_store: IDataStoreDispatcher, market: ContractAddress +) -> (u128, u128) { + let mut positive_impact_factor = data_store + .get_u128(keys::swap_impact_factor_key(market, true)); + let negative_impact_factor = data_store.get_u128(keys::swap_impact_factor_key(market, false)); + // if the positive impact factor is more than the negative impact factor, positions could be opened + // and closed immediately for a profit if the difference is sufficient to cover the position fees + if positive_impact_factor > negative_impact_factor { + positive_impact_factor = negative_impact_factor; + } + (positive_impact_factor, negative_impact_factor) } diff --git a/src/order/base_order_utils.cairo b/src/order/base_order_utils.cairo index a7ffd65ba..859aae89d 100644 --- a/src/order/base_order_utils.cairo +++ b/src/order/base_order_utils.cairo @@ -6,7 +6,6 @@ use integer::BoundedInt; use starknet::ContractAddress; // Local imports. -use satoru::utils::i128::{I128Div, u128_to_i128, i128_to_u128}; use satoru::data::data_store::{IDataStoreDispatcher, IDataStoreDispatcherTrait}; use satoru::event::event_emitter::{IEventEmitterDispatcher, IEventEmitterDispatcherTrait}; use satoru::oracle::oracle::{IOracleDispatcher, IOracleDispatcherTrait}; @@ -21,6 +20,8 @@ use satoru::utils::precision; use satoru::utils::store_arrays::{StoreMarketArray, StoreU64Array, StoreContractAddressArray}; use satoru::mock::referral_storage::{IReferralStorageDispatcher, IReferralStorageDispatcherTrait}; use satoru::utils::span32::Span32; +use satoru::utils::calc; +use satoru::utils::i128::{I128Div, I128Store, I128Serde}; #[derive(Drop, starknet::Store, Serde)] struct ExecuteOrderParams { @@ -414,7 +415,7 @@ fn get_execution_price_for_decrease( }; if adjusted_price_impact_usd < 0 - && i128_to_u128(-adjusted_price_impact_usd) > size_delta_usd { + && calc::to_unsigned(-adjusted_price_impact_usd) > size_delta_usd { panic( array![ OrderError::PRICE_IMPACT_LARGER_THAN_ORDER_SIZE, @@ -430,9 +431,9 @@ fn get_execution_price_for_decrease( let numerator = precision::mul_div_inum( position_size_in_usd, adjusted_price_impact_usd, position_size_in_tokens ); - let adjustment = numerator / u128_to_i128(size_delta_usd); + let adjustment = numerator / calc::to_signed(size_delta_usd, true); - let _execution_price: i128 = u128_to_i128(price) + adjustment; + let _execution_price: i128 = calc::to_signed(price, true) + adjustment; if _execution_price < 0 { panic( @@ -447,7 +448,7 @@ fn get_execution_price_for_decrease( ); } - execution_price = i128_to_u128(_execution_price); + execution_price = calc::to_unsigned(_execution_price); } // decrease order: diff --git a/src/position/position_utils.cairo b/src/position/position_utils.cairo index 846cb6372..492fe95d7 100644 --- a/src/position/position_utils.cairo +++ b/src/position/position_utils.cairo @@ -22,10 +22,7 @@ use satoru::order::order::{Order, SecondaryOrderType}; use satoru::mock::referral_storage::{IReferralStorageDispatcher, IReferralStorageDispatcherTrait}; use satoru::order::base_order_utils::ExecuteOrderParamsContracts; use satoru::price::price::{Price, PriceTrait}; -use satoru::utils::{ - precision, i128::{StoreI128, u128_to_i128, i128_to_u128, I128Serde, I128Div, I128Mul} -}; -use satoru::utils::calc::{roundup_division}; +use satoru::utils::{calc, precision, i128::{I128Store, I128Serde, I128Div, I128Mul}}; use satoru::referral::referral_utils; use satoru::order::order_vault::{IOrderVaultDispatcher, IOrderVaultDispatcherTrait}; @@ -257,13 +254,13 @@ fn get_position_pnl_usd( let execution_price = prices.index_token_price.pick_price_for_pnl(position.is_long, false); // position.sizeInUsd is the cost of the tokens, positionValue is the current worth of the tokens - cache.position_value = u128_to_i128(position.size_in_tokens * execution_price); + cache.position_value = calc::to_signed(position.size_in_tokens * execution_price, true); cache .total_position_pnl = if position.is_long { - cache.position_value - u128_to_i128(position.size_in_usd) + cache.position_value - calc::to_signed(position.size_in_usd, true) } else { - u128_to_i128(position.size_in_usd) - cache.position_value + calc::to_signed(position.size_in_usd, true) - cache.position_value }; cache.uncapped_total_position_pnl = cache.total_position_pnl; @@ -305,9 +302,9 @@ fn get_position_pnl_usd( cache .total_position_pnl = precision::mul_div_inum( - i128_to_u128(cache.total_position_pnl), + calc::to_unsigned(cache.total_position_pnl), cache.capped_pool_pnl, - i128_to_u128(cache.pool_pnl) + calc::to_unsigned(cache.pool_pnl) ); } } @@ -317,7 +314,7 @@ fn get_position_pnl_usd( if position.is_long { cache .size_delta_in_tokens = - roundup_division( + calc::roundup_division( position.size_in_tokens * size_delta_usd, position.size_in_usd ); } else { @@ -447,7 +444,7 @@ fn is_position_liquiditable( cache.collateral_usd = position.collateral_amount * cache.collateral_token_price.min; // calculate the usdDeltaForPriceImpact for fully closing the position - cache.usd_delta_for_price_impact = -u128_to_i128(position.size_in_usd); + cache.usd_delta_for_price_impact = calc::to_signed(position.size_in_usd, false); cache .price_impact_usd = position_pricing_utils::get_price_impact_usd( @@ -474,8 +471,8 @@ fn is_position_liquiditable( // this could result in very large price impact temporarily // cap the max negative price impact to prevent cascading liquidations - let max_negatice_price_impact = u128_to_i128( - precision::apply_factor_u128(position.size_in_usd, max_price_impact_factor) + let max_negatice_price_impact = calc::to_signed( + precision::apply_factor_u128(position.size_in_usd, max_price_impact_factor), true ); if cache.price_impact_usd < max_negatice_price_impact { cache.price_impact_usd = max_negatice_price_impact; @@ -501,13 +498,15 @@ fn is_position_liquiditable( // the position's pnl is counted as collateral for the liquidation check // as a position in profit should not be liquidated if the pnl is sufficient // to cover the position's fees - cache.remaining_collateral_usd = u128_to_i128(cache.collateral_usd) + cache.remaining_collateral_usd = calc::to_signed(cache.collateral_usd, true) + cache.position_pnl_usd + cache.price_impact_usd - - u128_to_i128(collateral_cost_usd); + - calc::to_signed(collateral_cost_usd, true); if should_validate_min_collateral_usd { - cache.min_collateral_usd = u128_to_i128(data_store.get_u128(keys::min_collateral_usd())); + cache + .min_collateral_usd = + calc::to_signed(data_store.get_u128(keys::min_collateral_usd()), true); if (cache.remaining_collateral_usd < cache.min_collateral_usd) { return (true, 'min collateral'); } @@ -523,8 +522,9 @@ fn is_position_liquiditable( // i.e. if the position does not have sufficient collateral after closing fees it is considered a liquidatable position cache .min_collateral_usd_for_leverage = - u128_to_i128( - precision::apply_factor_u128(position.size_in_usd, cache.min_collateral_factor) + calc::to_signed( + precision::apply_factor_u128(position.size_in_usd, cache.min_collateral_factor), + true ); if cache.remaining_collateral_usd <= cache.min_collateral_usd_for_leverage { return (true, 'min collateral for leverage'); @@ -574,8 +574,8 @@ fn will_position_collateral_be_sufficient( let collateral_token_price = market_utils::get_cached_token_price( collateral_token, market, prices ); - let mut remaining_collateral_usd = u128_to_i128(values.position_collateral_amount) - * u128_to_i128(collateral_token_price.min); + let mut remaining_collateral_usd = calc::to_signed(values.position_collateral_amount, true) + * calc::to_signed(collateral_token_price.min, true); // deduct realized pnl if it is negative since this would be paid from // the position's collateral if values.realized_pnl_usd < 0 { @@ -602,8 +602,8 @@ fn will_position_collateral_be_sufficient( if (min_collateral_factor_for_market > min_collateral_factor) { min_collateral_factor = min_collateral_factor_for_market; } - let min_collateral_usd_for_leverage = u128_to_i128( - precision::apply_factor_u128(values.position_size_in_usd, min_collateral_factor) + let min_collateral_usd_for_leverage = calc::to_signed( + precision::apply_factor_u128(values.position_size_in_usd, min_collateral_factor), true ); let will_be_sufficient: bool = remaining_collateral_usd >= min_collateral_usd_for_leverage; diff --git a/src/pricing/error.cairo b/src/pricing/error.cairo new file mode 100644 index 000000000..26d03c879 --- /dev/null +++ b/src/pricing/error.cairo @@ -0,0 +1,3 @@ +mod PricingError { + const USD_DELTA_EXCEEDS_POOL_VALUE: felt252 = 'usd_delta_exceeds_pool_value'; +} diff --git a/src/pricing/position_pricing_utils.cairo b/src/pricing/position_pricing_utils.cairo index 22f9dae11..05cf15dfa 100644 --- a/src/pricing/position_pricing_utils.cairo +++ b/src/pricing/position_pricing_utils.cairo @@ -14,7 +14,7 @@ use satoru::market::market::Market; use satoru::price::price::Price; use satoru::position::position::Position; use satoru::mock::referral_storage::{IReferralStorageDispatcher, IReferralStorageDispatcherTrait}; -use satoru::utils::i128::{StoreI128, I128Serde,}; +use satoru::utils::i128::{I128Store, I128Serde,}; /// Struct used in get_position_fees. #[derive(Drop, starknet::Store, Serde)] struct GetPositionFeesParams { diff --git a/src/pricing/pricing_utils.cairo b/src/pricing/pricing_utils.cairo index a81d132cb..2f83f120e 100644 --- a/src/pricing/pricing_utils.cairo +++ b/src/pricing/pricing_utils.cairo @@ -26,7 +26,7 @@ fn get_price_impact_usd_for_same_side_rebalance( /// a crossover in balance is for example if the long open interest is larger /// than the short open interest, and a short position is opened such that the /// short open interest becomes larger than the long open interest. -fn get_price_impact_usd_for_crossover_side_rebalance( +fn get_price_impact_usd_for_crossover_rebalance( initial_diff_usd: u128, next_diff_usd: u128, positive_impact_factor: u128, diff --git a/src/pricing/swap_pricing_utils.cairo b/src/pricing/swap_pricing_utils.cairo index cc1504c3a..670c2d095 100644 --- a/src/pricing/swap_pricing_utils.cairo +++ b/src/pricing/swap_pricing_utils.cairo @@ -10,15 +10,21 @@ use result::ResultTrait; // Local imports. use satoru::data::data_store::{IDataStoreDispatcher, IDataStoreDispatcherTrait}; use satoru::event::event_emitter::{IEventEmitterDispatcher, IEventEmitterDispatcherTrait}; +use satoru::data::keys; use satoru::market::market::Market; -use satoru::utils::i128::{StoreI128, I128Serde, I128Div, I128Mul, i128_to_u128, u128_to_i128}; +use satoru::market::market_utils; +use satoru::pricing::error::PricingError; +use satoru::pricing::pricing_utils; +use satoru::utils::calc; +use satoru::utils::precision; +use satoru::utils::i128::{I128Store, I128Serde, I128Div, I128Mul}; /// Struct used in get_price_impact_usd. -#[derive(Drop, starknet::Store, Serde)] +#[derive(Copy, Drop, starknet::Store, Serde)] struct GetPriceImpactUsdParams { /// The `DataStore` contract dispatcher. - dataStore: IDataStoreDispatcher, + data_store: IDataStoreDispatcher, /// The market to check. market: Market, /// The token to check balance for. @@ -76,14 +82,6 @@ impl DefaultSwapFees of Default { } } -/// Called by get_price_impact_usd(). -/// # Returns -/// The price impact in USD. -fn get_price_impact_usd(params: GetPriceImpactUsdParams) -> i128 { - // TODO - 0 -} - /// Get the price impact in USD /// /// Note that there will be some difference between the pool amounts used for @@ -99,16 +97,138 @@ fn get_price_impact_usd(params: GetPriceImpactUsdParams) -> i128 { /// * `params` - The necessary params to compute next pool amount in USD. /// # Returns /// New pool amount. -fn get_next_pool_amount_usd(params: GetPriceImpactUsdParams) -> PoolParams { - // TODO - PoolParams { - pool_usd_for_token_a: 0, - pool_usd_for_token_b: 0, - next_pool_usd_for_token_a: 0, - next_pool_usd_for_token_b: 0, +fn get_price_impact_usd(params: GetPriceImpactUsdParams) -> i128 { + let pool_params = get_next_pool_amount_usd(params); + + let price_impact_usd = get_price_impact_usd_(params.data_store, params.market, pool_params); + + // the virtual price impact calculation is skipped if the price impact + // is positive since the action is helping to balance the pool + // + // in case two virtual pools are unbalanced in a different direction + // e.g. pool0 has more WNT than USDC while pool1 has less WNT + // than USDT + // not skipping the virtual price impact calculation would lead to + // a negative price impact for any trade on either pools and would + // disincentivise the balancing of pools + if price_impact_usd >= 0 { + return price_impact_usd; + } + + // note that the virtual pool for the long token / short token may be different across pools + // e.g. ETH/USDC, ETH/USDT would have USDC and USDT as the short tokens + // the short token amount is multiplied by the price of the token in the current pool, e.g. if the swap + // is for the ETH/USDC pool, the combined USDC and USDT short token amounts is multiplied by the price of + // USDC to calculate the price impact, this should be reasonable most of the time unless there is a + // large depeg of one of the tokens, in which case it may be necessary to remove that market from being a virtual + // market, removal of virtual markets may lead to incorrect virtual token accounting, the feature to correct for + // this can be added if needed + let ( + has_virtual_inventory, + virtual_pool_amount_for_long_token, + virtual_pool_amount_for_short_token + ) = + market_utils::get_virtual_inventory_for_swaps( + params.data_store, params.market.market_token + ); + + if !has_virtual_inventory { + return price_impact_usd; + } + + let token_a_is_long = params.token_a == params.market.long_token; + let (virtual_pool_amount_for_token_a, virtual_pool_amount_for_token_b) = if token_a_is_long { + (virtual_pool_amount_for_long_token, virtual_pool_amount_for_short_token) + } else { + (virtual_pool_amount_for_short_token, virtual_pool_amount_for_long_token) + }; + + let pool_params_for_virtual_inventory = get_next_pool_amount_params( + params, virtual_pool_amount_for_token_a, virtual_pool_amount_for_token_b + ); + + let price_impact_usd_for_virtual_inventory = get_price_impact_usd_( + params.data_store, params.market, pool_params_for_virtual_inventory + ); + + if price_impact_usd_for_virtual_inventory < price_impact_usd { + price_impact_usd_for_virtual_inventory + } else { + price_impact_usd + } +} + +/// Called by get_price_impact_usd(). +/// # Arguments +/// * `data_store` - DataStore +/// * `market` - the trading market +/// * `pool_params` - PoolParams +/// # Returns +/// The price impact in USD. +fn get_price_impact_usd_( + data_store: IDataStoreDispatcher, market: Market, pool_params: PoolParams, +) -> i128 { + let initial_diff_usd = calc::diff( + pool_params.pool_usd_for_token_a, pool_params.pool_usd_for_token_b + ); + let next_diff_usd = calc::diff( + pool_params.next_pool_usd_for_token_a, pool_params.next_pool_usd_for_token_b + ); + + // check whether an improvement in balance comes from causing the balance to switch sides + // for example, if there is $2000 of ETH and $1000 of USDC in the pool + // adding $1999 USDC into the pool will reduce absolute balance from $1000 to $999 but it does not + // help rebalance the pool much, the isSameSideRebalance value helps avoid gaming using this case + + let a_lte_b = pool_params.pool_usd_for_token_a <= pool_params.pool_usd_for_token_b; + let next_a_lte_b = pool_params + .next_pool_usd_for_token_a <= pool_params + .next_pool_usd_for_token_b; + let is_same_side_rebalance = a_lte_b == next_a_lte_b; + let impact_exponent_factor = data_store + .get_u128(keys::swap_impact_exponent_factor_key(market.market_token)); + + if is_same_side_rebalance { + let has_positive_impact = next_diff_usd < initial_diff_usd; + let impact_factor = market_utils::get_adjusted_swap_impact_factor( + data_store, market.market_token, has_positive_impact + ); + + pricing_utils::get_price_impact_usd_for_same_side_rebalance( + initial_diff_usd, next_diff_usd, impact_factor, impact_exponent_factor + ) + } else { + let (positive_impact_factor, negative_impact_factor) = + market_utils::get_adjusted_swap_impact_factors( + data_store, market.market_token + ); + + pricing_utils::get_price_impact_usd_for_crossover_rebalance( + initial_diff_usd, + next_diff_usd, + positive_impact_factor, + negative_impact_factor, + impact_exponent_factor + ) } } +/// Get the next pool amounts in USD +/// # Arguments +/// `params` - GetPriceImpactUsdParams +/// # Returns +/// PoolParams +fn get_next_pool_amount_usd(params: GetPriceImpactUsdParams) -> PoolParams { + let pool_amount_for_token_a = market_utils::get_pool_amount( + params.data_store, @params.market, params.token_a + ); + let pool_amount_for_token_b = market_utils::get_pool_amount( + params.data_store, @params.market, params.token_b + ); + + get_next_pool_amount_params(params, pool_amount_for_token_a, pool_amount_for_token_b) +} + /// Get the new pool values. /// # Arguments /// * `params` - The necessary params to compute price impact. @@ -119,12 +239,40 @@ fn get_next_pool_amount_usd(params: GetPriceImpactUsdParams) -> PoolParams { fn get_next_pool_amount_params( params: GetPriceImpactUsdParams, pool_amount_for_token_a: u128, pool_amount_for_token_b: u128 ) -> PoolParams { - // TODO + let pool_usd_for_token_a = pool_amount_for_token_a * params.price_for_token_a; + let pool_usd_for_token_b = pool_amount_for_token_b * params.price_for_token_b; + if params.usd_delta_for_token_a < 0 + && calc::to_unsigned(-params.usd_delta_for_token_a) > pool_usd_for_token_a { + panic( + array![ + PricingError::USD_DELTA_EXCEEDS_POOL_VALUE, + params.usd_delta_for_token_a.into(), + pool_usd_for_token_a.into() + ] + ); + } + if params.usd_delta_for_token_b < 0 + && calc::to_unsigned(-params.usd_delta_for_token_b) > pool_usd_for_token_b { + panic( + array![ + PricingError::USD_DELTA_EXCEEDS_POOL_VALUE, + params.usd_delta_for_token_b.into(), + pool_usd_for_token_b.into() + ] + ); + } + let next_pool_usd_for_token_a = calc::sum_return_uint_128( + pool_usd_for_token_a, params.usd_delta_for_token_a + ); + let next_pool_usd_for_token_b = calc::sum_return_uint_128( + pool_usd_for_token_b, params.usd_delta_for_token_b + ); + PoolParams { - pool_usd_for_token_a: 0, - pool_usd_for_token_b: 0, - next_pool_usd_for_token_a: 0, - next_pool_usd_for_token_b: 0, + pool_usd_for_token_a, + pool_usd_for_token_b, + next_pool_usd_for_token_a, + next_pool_usd_for_token_b, } } @@ -144,14 +292,32 @@ fn get_swap_fees( for_positive_impact: bool, ui_fee_receiver: ContractAddress, ) -> SwapFees { - // TODO - let address_zero: ContractAddress = 0.try_into().unwrap(); + // note that since it is possible to incur both positive and negative price impact values + // and the negative price impact factor may be larger than the positive impact factor + // it is possible for the balance to be improved overall but for the price impact to still be negative + // in this case the fee factor for the negative price impact would be charged + // a user could split the order into two, to incur a smaller fee, reducing the fee through this should not be a large issue + + let fee_factor = data_store + .get_u128(keys::swap_fee_factor_key(market_token, for_positive_impact)); + let swap_fee_receiver_factor = data_store.get_u128(keys::swap_fee_receiver_factor()); + + let fee_amount = precision::apply_factor_u128(amount, fee_factor); + + let fee_receiver_amount = precision::apply_factor_u128(fee_amount, swap_fee_receiver_factor); + let fee_amount_for_pool = fee_amount - fee_receiver_amount; + + let ui_fee_receiver_factor = market_utils::get_ui_fee_factor(data_store, ui_fee_receiver); + let ui_fee_amount = precision::apply_factor_u128(amount, ui_fee_receiver_factor); + + let amount_after_fees = amount - fee_amount - ui_fee_amount; + SwapFees { - fee_receiver_amount: 0, - fee_amount_for_pool: 0, - amount_after_fees: 0, - ui_fee_receiver: address_zero, - ui_fee_receiver_factor: 0, - ui_fee_amount: 0, + fee_receiver_amount, + fee_amount_for_pool, + amount_after_fees, + ui_fee_receiver, + ui_fee_receiver_factor, + ui_fee_amount, } } diff --git a/src/reader/reader.cairo b/src/reader/reader.cairo index 6480cf8c8..eb23265aa 100644 --- a/src/reader/reader.cairo +++ b/src/reader/reader.cairo @@ -29,7 +29,7 @@ use satoru::withdrawal::withdrawal::Withdrawal; use satoru::position::{position_utils, position::Position}; use satoru::pricing::swap_pricing_utils::SwapFees; use satoru::deposit::deposit::Deposit; -use satoru::utils::{i128::{StoreI128, I128Serde, u128_to_i128, i128_to_u128, I128Div, I128Mul}}; +use satoru::utils::{i128::{I128Store, I128Serde, I128Div, I128Mul}}; #[derive(Drop, starknet::Store, Serde)] struct VirtualInventory { @@ -450,7 +450,7 @@ mod Reader { market_utils, market_utils::GetNextFundingAmountPerSizeResult, market::Market, market_utils::MarketPrices, market_pool_value_info::MarketPoolValueInfo, }; - use satoru::utils::{i128::{StoreI128, I128Serde, u128_to_i128, i128_to_u128, I128Div, I128Mul}}; + use satoru::utils::{i128::{I128Store, I128Serde, I128Div, I128Mul}}; use satoru::withdrawal::withdrawal::Withdrawal; use satoru::position::{position_utils, position::Position}; use satoru::pricing::swap_pricing_utils::SwapFees; diff --git a/src/reader/reader_pricing_utils.cairo b/src/reader/reader_pricing_utils.cairo index ee7a023e2..ce1fe69cf 100644 --- a/src/reader/reader_pricing_utils.cairo +++ b/src/reader/reader_pricing_utils.cairo @@ -27,6 +27,7 @@ use satoru::pricing::{ swap_pricing_utils::{SwapFees, get_swap_fees, get_price_impact_usd, GetPriceImpactUsdParams} }; use satoru::reader::error::ReaderError; +use satoru::utils::calc; use satoru::utils::span32::{Span32, Array32Trait}; use satoru::swap::{ swap_utils::SwapCache, swap_handler::{ISwapHandlerDispatcher, ISwapHandlerDispatcherTrait} @@ -38,7 +39,7 @@ use satoru::event::event_emitter::{IEventEmitterDispatcher, IEventEmitterDispatc use satoru::oracle::oracle::{IOracleDispatcher, IOracleDispatcherTrait}; use satoru::mock::referral_storage::{IReferralStorageDispatcher, IReferralStorageDispatcherTrait}; -use satoru::utils::i128::{StoreI128, I128Serde, I128Div, I128Mul, i128_to_u128, u128_to_i128}; +use satoru::utils::i128::{I128Store, I128Serde, I128Div, I128Mul}; #[derive(Drop, starknet::Store, Serde)] struct ExecutionPriceResult { @@ -96,14 +97,14 @@ fn get_swap_amount_out( cache.token_out_price = get_cached_token_price(cache.token_out, market, prices); let param: GetPriceImpactUsdParams = GetPriceImpactUsdParams { - dataStore: data_store, + data_store: data_store, market: market, token_a: token_in, token_b: cache.token_out, price_for_token_a: cache.token_in_price.mid_price(), price_for_token_b: cache.token_out_price.mid_price(), - usd_delta_for_token_a: u128_to_i128(amount_in * cache.token_in_price.mid_price()), - usd_delta_for_token_b: -u128_to_i128(amount_in * cache.token_in_price.mid_price()) + usd_delta_for_token_a: calc::to_signed(amount_in * cache.token_in_price.mid_price(), true), + usd_delta_for_token_b: calc::to_signed(amount_in * cache.token_in_price.mid_price(), false) }; let price_impact_usd: i128 = get_price_impact_usd(param); @@ -135,7 +136,7 @@ fn get_swap_amount_out( price_impact_usd ); - cache.amount_out += i128_to_u128(impact_amount); + cache.amount_out += calc::to_unsigned(impact_amount); } else { // when there is a negative price impact factor, // less of the input amount is sent to the pool @@ -148,7 +149,7 @@ fn get_swap_amount_out( data_store, market.market_token, token_in, cache.token_in_price, price_impact_usd ); - cache.amount_in = fees.amount_after_fees - i128_to_u128(-impact_amount); + cache.amount_in = fees.amount_after_fees - calc::to_unsigned(-impact_amount); cache.amount_out = cache.amount_in * cache.token_in_price.min / cache.token_out_price.max; cache.pool_amount_out = cache.amount_out; } @@ -185,7 +186,7 @@ fn get_execution_price( } else { -size_delta_usd }; - params.order.size_delta_usd = i128_to_u128(size_delta_usd_abs); + params.order.size_delta_usd = calc::to_unsigned(size_delta_usd_abs); params.order.is_long = is_long; let is_increase: bool = size_delta_usd > 0; @@ -254,14 +255,14 @@ fn get_swap_price_impact( let mut cache: SwapCache = Default::default(); let param: GetPriceImpactUsdParams = GetPriceImpactUsdParams { - dataStore: data_store, + data_store: data_store, market: market, token_a: token_in, token_b: token_out, price_for_token_a: token_in_price.mid_price(), price_for_token_b: token_out_price.mid_price(), - usd_delta_for_token_a: u128_to_i128(amount_in * token_in_price.mid_price()), - usd_delta_for_token_b: -u128_to_i128(amount_in * token_in_price.mid_price()) + usd_delta_for_token_a: calc::to_signed(amount_in * token_in_price.mid_price(), true), + usd_delta_for_token_b: calc::to_signed(amount_in * token_in_price.mid_price(), false) }; let price_impact_usd_before_cap: i128 = get_price_impact_usd(param); diff --git a/src/reader/reader_utils.cairo b/src/reader/reader_utils.cairo index f9331b8f7..f4c3cfbf8 100644 --- a/src/reader/reader_utils.cairo +++ b/src/reader/reader_utils.cairo @@ -26,7 +26,7 @@ use satoru::pricing::position_pricing_utils::PositionReferralFees; use satoru::pricing::position_pricing_utils::PositionFundingFees; use satoru::pricing::position_pricing_utils::PositionUiFees; use satoru::mock::referral_storage::{IReferralStorageDispatcher, IReferralStorageDispatcherTrait}; -use satoru::utils::i128::{StoreI128, u128_to_i128, I128Serde, I128Div, I128Mul}; +use satoru::utils::i128::{I128Store, I128Serde, I128Div, I128Mul}; #[derive(Drop, starknet::Store, Serde)] struct PositionInfo { diff --git a/src/swap/error.cairo b/src/swap/error.cairo index a29cbae6a..b756f4c80 100644 --- a/src/swap/error.cairo +++ b/src/swap/error.cairo @@ -16,8 +16,8 @@ mod SwapError { data.append(expected_token.into()); panic(data) } - // TODO: negative_impact_amount should be a i128 - fn SWAP_PRICE_IMPACT_EXCEEDS_AMOUNT_IN(amount_after_fees: u128, negative_impact_amount: u128) { + + fn SWAP_PRICE_IMPACT_EXCEEDS_AMOUNT_IN(amount_after_fees: u128, negative_impact_amount: i128) { let mut data = array!['price impact exceeds amount']; data.append(amount_after_fees.into()); data.append(negative_impact_amount.into()); diff --git a/src/swap/swap_handler.cairo b/src/swap/swap_handler.cairo index b89880865..6ed816c72 100644 --- a/src/swap/swap_handler.cairo +++ b/src/swap/swap_handler.cairo @@ -34,6 +34,7 @@ mod SwapHandler { use satoru::swap::swap_utils::SwapParams; use satoru::swap::swap_utils; use satoru::role::role_module::{RoleModule, IRoleModule}; + use satoru::utils::i128::{I128Store, I128Serde}; // ************************************************************************* // STORAGE diff --git a/src/swap/swap_utils.cairo b/src/swap/swap_utils.cairo index 911adb0a0..9e49589f0 100644 --- a/src/swap/swap_utils.cairo +++ b/src/swap/swap_utils.cairo @@ -3,12 +3,7 @@ // ************************************************************************* // Core lib imports. use starknet::{ContractAddress, contract_address_const}; -use result::ResultTrait; -use core::traits::{Into, TryInto}; use core::integer::I128Neg; -use satoru::utils::i128::{ - StoreI128, I128Serde, I128Div, I128Mul, I128Default, i128_to_u128, u128_to_i128 -}; // Local imports. @@ -17,7 +12,8 @@ use satoru::event::event_emitter::{IEventEmitterDispatcher, IEventEmitterDispatc use satoru::bank::bank::{IBankDispatcher, IBankDispatcherTrait}; use satoru::market::{market::Market, market_utils}; use satoru::fee::fee_utils; -use satoru::utils::{store_arrays::StoreMarketSpan, traits::ContractAddressDefault}; +use satoru::utils::{calc, store_arrays::StoreMarketSpan, traits::ContractAddressDefault}; +use satoru::utils::i128::{I128Store, I128Serde, I128Div, I128Mul, I128Default}; use satoru::oracle::oracle::{IOracleDispatcher, IOracleDispatcherTrait}; use satoru::swap::error::SwapError; use satoru::data::keys; @@ -195,20 +191,17 @@ fn _swap(params: @SwapParams, _params: @_SwapParams) -> (ContractAddress, u128) * cache.token_out_price.mid_price()) .into(); + let usd_delta = *_params.amount_in * cache.token_out_price.mid_price(); let price_impact_usd = swap_pricing_utils::get_price_impact_usd( swap_pricing_utils::GetPriceImpactUsdParams { - dataStore: *params.data_store, + data_store: *params.data_store, market: *_params.market, token_a: *_params.token_in, token_b: cache.token_out, price_for_token_a: cache.token_in_price.mid_price(), price_for_token_b: cache.token_out_price.mid_price(), - usd_delta_for_token_a: u128_to_i128( - *_params.amount_in * cache.token_in_price.mid_price() - ), - usd_delta_for_token_b: -u128_to_i128( - *_params.amount_in * cache.token_in_price.mid_price() - ) + usd_delta_for_token_a: calc::to_signed(usd_delta, true), + usd_delta_for_token_b: calc::to_signed(usd_delta, false), } ); @@ -260,7 +253,7 @@ fn _swap(params: @SwapParams, _params: @_SwapParams) -> (ContractAddress, u128) price_impact_usd ); - cache.amount_out += i128_to_u128(price_impact_amount); + cache.amount_out += calc::to_unsigned(price_impact_amount); } else { // when there is a negative price impact factor, // less of the input amount is sent to the pool @@ -277,13 +270,12 @@ fn _swap(params: @SwapParams, _params: @_SwapParams) -> (ContractAddress, u128) price_impact_usd ); - // TODO should be -price_impact_amount when i128 supported - if (fees.amount_after_fees <= i128_to_u128(price_impact_amount)) { + if fees.amount_after_fees <= calc::to_unsigned(-price_impact_amount) { SwapError::SWAP_PRICE_IMPACT_EXCEEDS_AMOUNT_IN( - fees.amount_after_fees, i128_to_u128(price_impact_amount) + fees.amount_after_fees, price_impact_amount ); } - cache.amount_in = fees.amount_after_fees - i128_to_u128(price_impact_amount); + cache.amount_in = fees.amount_after_fees - calc::to_unsigned(-price_impact_amount); cache.amount_out = cache.amount_in * cache.token_in_price.min / cache.token_out_price.max; cache.pool_amount_out = cache.amount_out; } @@ -369,7 +361,7 @@ fn _swap(params: @SwapParams, _params: @_SwapParams) -> (ContractAddress, u128) cache.amount_in, cache.amount_out, price_impact_usd, - price_impact_amount + price_impact_amount, ); (*params.event_emitter) diff --git a/src/tests/event/test_position_events_emitted.cairo b/src/tests/event/test_position_events_emitted.cairo index 8a70574e8..4ca70134a 100644 --- a/src/tests/event/test_position_events_emitted.cairo +++ b/src/tests/event/test_position_events_emitted.cairo @@ -14,7 +14,7 @@ use satoru::pricing::position_pricing_utils::{ use satoru::order::order::OrderType; use satoru::price::price::Price; use satoru::event::event_emitter::{IEventEmitterDispatcher, IEventEmitterDispatcherTrait}; -use satoru::utils::i128::{StoreI128, u128_to_i128, I128Serde, I128Div, I128Mul}; +use satoru::utils::i128::{I128Store, I128Serde, I128Div, I128Mul}; #[test] fn given_normal_conditions_when_emit_position_increase_then_works() { diff --git a/src/tests/pricing/test_swap_pricing_utils.cairo b/src/tests/pricing/test_swap_pricing_utils.cairo new file mode 100644 index 000000000..fab17010c --- /dev/null +++ b/src/tests/pricing/test_swap_pricing_utils.cairo @@ -0,0 +1,131 @@ +use satoru::data::data_store::IDataStoreDispatcherTrait; +use satoru::data::keys; +use satoru::pricing::swap_pricing_utils::{ + GetPriceImpactUsdParams, get_price_impact_usd_, get_price_impact_usd, get_next_pool_amount_usd, + get_swap_fees +}; +use satoru::market::market::Market; +use satoru::utils::calc; +use satoru::tests_lib::{setup, teardown}; + +#[test] +fn given_normal_conditions_when_swap_pricing_utils_functions_then_works() { + // ********************************************************************************************* + // * SETUP * + // ********************************************************************************************* + let (_, _, data_store) = setup(); + + let market_token = 'market_token'.try_into().unwrap(); + let index_token = 'index_token'.try_into().unwrap(); + let long_token = 'long_token'.try_into().unwrap(); + let short_token = 'short_token'.try_into().unwrap(); + + data_store.set_u128(keys::pool_amount_key(market_token, long_token), 1000); + data_store.set_u128(keys::pool_amount_key(market_token, short_token), 1000); + + // ********************************************************************************************* + // * TEST LOGIC * + // ********************************************************************************************* + + let params = GetPriceImpactUsdParams { + data_store, + market: Market { market_token, index_token, long_token, short_token }, + token_a: long_token, + token_b: short_token, + price_for_token_a: 101, + price_for_token_b: 99, + usd_delta_for_token_a: 5, + usd_delta_for_token_b: 4, + }; + + let impact = get_price_impact_usd(params); + // TODO change to real value when precision::apply_exponent_factor is implemented + assert(impact == 0, 'foo'); + + // ********************************************************************************************* + // * TEARDOWN * + // ********************************************************************************************* + teardown(data_store.contract_address); +} + +#[test] +fn given_normal_conditions_when_get_next_pool_amount_usd_then_works() { + // ********************************************************************************************* + // * SETUP * + // ********************************************************************************************* + let (_, _, data_store) = setup(); + + let market_token = 'market_token'.try_into().unwrap(); + let index_token = 'index_token'.try_into().unwrap(); + let long_token = 'long_token'.try_into().unwrap(); + let short_token = 'short_token'.try_into().unwrap(); + + data_store.set_u128(keys::pool_amount_key(market_token, long_token), 1000); + data_store.set_u128(keys::pool_amount_key(market_token, short_token), 1000); + data_store.set_u128(keys::swap_impact_factor_key(market_token, false), 10); + data_store.set_u128(keys::swap_impact_factor_key(market_token, true), 10); + data_store.set_u128(keys::swap_impact_exponent_factor_key(market_token), 10); + + // ********************************************************************************************* + // * TEST LOGIC * + // ********************************************************************************************* + + let params = GetPriceImpactUsdParams { + data_store, + market: Market { market_token, index_token, long_token, short_token }, + token_a: long_token, + token_b: short_token, + price_for_token_a: 101, + price_for_token_b: 99, + usd_delta_for_token_a: 5, + usd_delta_for_token_b: 4, + }; + + let pool_params = get_next_pool_amount_usd(params); + assert(pool_params.pool_usd_for_token_a == 101000, 'invalid'); + assert(pool_params.pool_usd_for_token_b == 99000, 'invalid'); + assert(pool_params.next_pool_usd_for_token_a == 101005, 'invalid'); + assert(pool_params.next_pool_usd_for_token_b == 99004, 'invalid'); + + // ********************************************************************************************* + // * TEARDOWN * + // ********************************************************************************************* + teardown(data_store.contract_address); +} + +#[test] +fn given_normal_conditions_when_get_swap_fees_then_works() { + // ********************************************************************************************* + // * SETUP * + // ********************************************************************************************* + let (_, _, data_store) = setup(); + + let market_token = 'market_token'.try_into().unwrap(); + let ui_fee_receiver = 'ui_fee_receiver'.try_into().unwrap(); + let for_positive_impact = true; + + data_store.set_u128(keys::swap_fee_factor_key(market_token, for_positive_impact), 5); + data_store.set_u128(keys::swap_fee_receiver_factor(), 10); + data_store.set_u128(keys::max_ui_fee_factor(), 9); + data_store.set_u128(keys::ui_fee_factor_key(ui_fee_receiver), 9); + + // ********************************************************************************************* + // * TEST LOGIC * + // ********************************************************************************************* + + let amount = 1000; + let fees = get_swap_fees( + data_store, market_token, amount, for_positive_impact, ui_fee_receiver + ); + + assert(fees.fee_receiver_amount == 0, 'invalid'); + assert(fees.fee_amount_for_pool == 0, 'invalid'); + assert(fees.amount_after_fees == 0x03e8, 'invalid'); + assert(fees.ui_fee_receiver_factor == 9, 'invalid'); + assert(fees.ui_fee_amount == 0, 'invalid'); + + // ********************************************************************************************* + // * TEARDOWN * + // ********************************************************************************************* + teardown(data_store.contract_address); +} diff --git a/src/tests/utils/test_i128.cairo b/src/tests/utils/test_i128.cairo index aeda8a5e0..307d3680e 100644 --- a/src/tests/utils/test_i128.cairo +++ b/src/tests/utils/test_i128.cairo @@ -73,7 +73,7 @@ trait ITestI128Storage { #[starknet::contract] mod test_i128_storage_contract { - use satoru::utils::i128::{StoreI128, I128Serde}; + use satoru::utils::i128::{I128Store, I128Serde}; use super::ITestI128Storage; diff --git a/src/token/token_utils.cairo b/src/token/token_utils.cairo index 66407a400..30b1d501a 100644 --- a/src/token/token_utils.cairo +++ b/src/token/token_utils.cairo @@ -16,7 +16,7 @@ fn fee_token(data_store: IDataStoreDispatcher) -> ContractAddress { // Transfers the specified amount of `token` from the caller to `receiver`. // # Arguments -// dataStore - The data store that contains the `tokenTransferGasLimit` for the specified `token`. +// data_store - The data store that contains the `tokenTransferGasLimit` for the specified `token`. // token - The address of the ERC20 token that is being transferred. // receiver - The address of the recipient of the `token` transfer. // amount - The amount of `token` to transfer. diff --git a/src/utils/calc.cairo b/src/utils/calc.cairo index 9b2fc8c07..4ff222f3c 100644 --- a/src/utils/calc.cairo +++ b/src/utils/calc.cairo @@ -47,7 +47,7 @@ fn roundup_magnitude_division(a: i128, b: u128) -> i128 { } } -/// Adds two numbers together and return an u256 value, treating the second number as a signed integer, +/// Adds two numbers together and return an u128 value, treating the second number as a signed integer, /// # Arguments /// * `a` - first number. /// * `b` - second number. @@ -153,15 +153,24 @@ fn bounded_sub(a: i128, b: i128) -> i128 { /// # Return /// The signed integer. fn to_signed(a: u128, is_positive: bool) -> i128 { + let a_felt: felt252 = a.into(); + let a_signed = a_felt.try_into().expect('i128 Overflow'); if is_positive { - let a_felt: felt252 = a.into(); - a_felt.try_into().expect('i128 Overflow') + a_signed } else { - let a_felt: felt252 = a.into(); - -a_felt.try_into().expect('i128 Overflow') + -a_signed } } +/// Converts the given signed integer to an unsigned integer, panics otherwise +/// # Return +/// The unsigned integer. +fn to_unsigned(value: i128) -> u128 { + assert(value >= 0, 'to_unsigned: value is negative'); + let value: felt252 = value.into(); + value.try_into().unwrap() +} + // TODO use BoundedInt::max() && BoundedInt::mint() when possible // Can't impl trait BoundedInt because of "-" that can panic (unless I can do it without using the minus operator) fn max_i128() -> i128 { diff --git a/src/utils/i128.cairo b/src/utils/i128.cairo index 8bc71fe79..45217d305 100644 --- a/src/utils/i128.cairo +++ b/src/utils/i128.cairo @@ -7,6 +7,12 @@ use starknet::{ }; use integer::BoundedInt; +impl I128Default of Default { + #[inline(always)] + fn default() -> i128 { + 0 + } +} impl I128Div of Div { fn div(lhs: i128, rhs: i128) -> i128 { @@ -47,10 +53,10 @@ fn abs(signed_integer: i128) -> u128 { response.try_into().expect('u128 Overflow') } -impl StoreI128 of Store { +impl I128Store of Store { fn read(address_domain: u32, base: StorageBaseAddress) -> SyscallResult { Result::Ok( - Store::::read(address_domain, base)?.try_into().expect('StoreI128 - non i128') + Store::::read(address_domain, base)?.try_into().expect('I128Store - non i128') ) } #[inline(always)] @@ -64,7 +70,7 @@ impl StoreI128 of Store { Result::Ok( Store::::read_at_offset(address_domain, base, offset)? .try_into() - .expect('StoreI128 - non i128') + .expect('I128Store - non i128') ) } #[inline(always)] @@ -89,22 +95,3 @@ impl I128Serde of Serde { Option::Some(i128_val) } } - -fn u128_to_i128(value: u128) -> i128 { - assert(value <= BoundedInt::max(), 'u128_to_i128: value too large'); - let value: felt252 = value.into(); - value.try_into().unwrap() -} - -fn i128_to_u128(value: i128) -> u128 { - assert(value >= 0, 'i128_to_u128: value is negative'); - let value: felt252 = value.into(); - value.try_into().unwrap() -} - -impl I128Default of Default { - #[inline(always)] - fn default() -> i128 { - 0 - } -} diff --git a/src/utils/test_pricing_utils.cairo b/src/utils/test_pricing_utils.cairo index e26bcf485..8ff2f97b9 100644 --- a/src/utils/test_pricing_utils.cairo +++ b/src/utils/test_pricing_utils.cairo @@ -1,6 +1,6 @@ use satoru::pricing::pricing_utils::{ apply_impact_factor, get_price_impact_usd_for_same_side_rebalance, - get_price_impact_usd_for_crossover_side_rebalance + get_price_impact_usd_for_crossover_rebalance }; // ************************************************************************* // Tests for apply_impact_factor function @@ -22,15 +22,15 @@ fn test_get_price_impact_usd_for_same_side_rebalance_positive_impact() { //TODO // ************************************************************************* -// Tests for get_price_impact_usd_for_crossover_side_rebalance function +// Tests for get_price_impact_usd_for_crossover_rebalance function // ************************************************************************* #[test] fn test_get_price_impact_usd_for_crossover_side_rebalance_positive_impact() { //TODO finish this test and add others test once apply_exponent_factor is implemented - //assert(get_price_impact_usd_for_crossover_side_rebalance(x, y, z, k) == r, 'should be r'); + //assert(get_price_impact_usd_for_crossover_rebalance(x, y, z, k) == r, 'should be r'); assert(1 == 1, ''); } #[test] -fn test_get_price_impact_usd_for_crossover_side_rebalance_negative_impact() { //assert(get_price_impact_usd_for_crossover_side_rebalance(x, y, z, k) == r, 'should be r'); +fn test_get_price_impact_usd_for_crossover_side_rebalance_negative_impact() { //assert(get_price_impact_usd_for_crossover_rebalance(x, y, z, k) == r, 'should be r'); assert(1 == 1, ''); }