diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 50d2b9b8..8606153e 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -13,7 +13,7 @@ jobs: - name: Install Semgrep run: | - pip install semgrep + pip install semgrep==1.45.0 - name: Run Semgrep run: semgrep --config https://github.com/avnu-labs/semgrep-cairo-rules/releases/download/v0.0.1/cairo-rules.yaml ./src > semgrep-output.txt - name: Save Semgrep Output as an Artifact diff --git a/README.md b/README.md index 8a9de13c..2f820537 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ snforge ## 🚀 Deploy -To deploy contracts of the saturo, you first need to setup a smart wallet : +To deploy the contracts of Satoru, you first need to setup a smart wallet : - Create a signer by following this tutorial : [Signers](https://book.starkli.rs/signers) @@ -63,6 +63,21 @@ cd scripts ./deploy_contract.sh ``` +## Deployed Contracts + +- RoleStore: 0x07eacab18c343f30edfa9336b8eacce9bc56303d43c92609a88e8da25177f5b3 +- DataStore: 0x0549539da18f4d574211365b6abd678ef940444b579900efedcb935210c41481 +- OrderVault: 0x01f1252d6d02feb14cfa88beff415e1524d1cebb31870056567aae257104b6fd +- Router: 0x00dd0912017ee7c8151555394380acd1012a814916d384b12ca64afa0eae2bc5 +- EventEmitter: 0x0284ae712869c0af4f538e9297e6965d3c9ba9110830944047de8d35da7ea447 +- MarketToken: 0x044391e9498f440cc41ace136ea317f6bfa2080311085d1846529e421974a1d3 +- MarketFactory: 0x05766918626a91ca83f52003eb03bbf1f13174aa22e340c8057d8d5d6affbfcf +- WithdrawalVault: 0x050c83c2bc74cc50676fdd5598b40f9d0d6d5ccf6ea3478a7999e29473da03f1 +- SwapHandler: 0x039aa67b479f4870878ec6d3002f9fa9b8e98d4d3d10c1f32b5d394a456aab28 +- ReferralStorage: 0x0189463034c24b2cb091dcb515287bea13a4767534f09e52692a4cdc30254001 +- DepositVault: 0x07d435e7ab3a5cd4b872e5725b02898833cb9a7c62e2d9a6a9db324d61e2925e + + ## 📚 Resources Here are some resources to help you get started: diff --git a/src/deposit/execute_deposit_utils.cairo b/src/deposit/execute_deposit_utils.cairo index 68ddd1ca..a44d0112 100644 --- a/src/deposit/execute_deposit_utils.cairo +++ b/src/deposit/execute_deposit_utils.cairo @@ -36,7 +36,7 @@ use satoru::pricing::swap_pricing_utils::{ use satoru::swap::swap_utils; use satoru::swap::error::SwapError; use satoru::utils::{ - calc::{to_unsigned, to_signed}, i128::i128, precision, span32::Span32, + calc::{to_unsigned, to_signed}, i128::{i128, i128_new, i128_neg}, precision, span32::Span32, starknet_utils::{sn_gasleft, sn_gasprice} }; @@ -86,7 +86,7 @@ struct _ExecuteDepositParams { /// `amount` Amount of token_in. amount: u128, /// `price_impact_usd` Price impact in USD. - price_impact_usd: u128 + price_impact_usd: i128 } #[derive(Drop, Default)] @@ -102,7 +102,6 @@ struct ExecuteDepositCache { /// Executes a deposit. /// # Arguments /// * `params` - ExecuteDepositParams. -#[inline(always)] fn execute_deposit(params: ExecuteDepositParams) { // 63/64 gas is forwarded to external calls, reduce the startingGas to account for this let starting_gas = params.starting_gas - sn_gasleft(array![]) / 63; @@ -180,12 +179,12 @@ fn execute_deposit(params: ExecuteDepositParams) { price_for_token_a: prices.long_token_price.mid_price(), price_for_token_b: prices.short_token_price.mid_price(), usd_delta_for_token_a: to_signed(cache.long_token_usd, true), - usd_delta_for_token_b: to_signed(cache.short_token_usd, false), + usd_delta_for_token_b: to_signed(cache.short_token_usd, true), } ); if cache.long_token_amount > 0 { - let _params = _ExecuteDepositParams { + let mut _params = _ExecuteDepositParams { market: market, account: deposit.account, receiver: deposit.receiver, @@ -195,16 +194,16 @@ fn execute_deposit(params: ExecuteDepositParams) { token_in_price: prices.long_token_price, token_out_price: prices.short_token_price, amount: cache.long_token_amount, - price_impact_usd: precision::mul_div( - to_unsigned(cache.price_impact_usd), + price_impact_usd: precision::mul_div_ival( + cache.price_impact_usd, cache.long_token_usd, cache.long_token_usd + cache.short_token_usd ) }; - cache.received_market_tokens += execute_deposit_helper(@params, @_params); + cache.received_market_tokens += execute_deposit_helper(@params, ref _params); } else if cache.short_token_amount > 0 { - let _params = _ExecuteDepositParams { + let mut _params = _ExecuteDepositParams { market: market, account: deposit.account, receiver: deposit.receiver, @@ -214,23 +213,21 @@ fn execute_deposit(params: ExecuteDepositParams) { token_in_price: prices.short_token_price, token_out_price: prices.long_token_price, amount: cache.short_token_amount, - price_impact_usd: precision::mul_div( - to_unsigned(cache.price_impact_usd), + price_impact_usd: precision::mul_div_ival( + cache.price_impact_usd, cache.short_token_usd, cache.long_token_usd + cache.short_token_usd ) }; - cache.received_market_tokens += execute_deposit_helper(@params, @_params); + cache.received_market_tokens += execute_deposit_helper(@params, ref _params); } if cache.received_market_tokens < deposit.min_market_tokens { DepositError::MIN_MARKET_TOKENS(cache.received_market_tokens, deposit.min_market_tokens); } - market_utils::validate_market_token_balance_with_address( - params.data_store, market.market_token - ); + market_utils::validate_market_token_balance_check(params.data_store, market); (params.event_emitter) .emit_deposit_executed( @@ -261,22 +258,24 @@ fn execute_deposit(params: ExecuteDepositParams) { /// * `params` - @ExecuteDepositParams. /// * `_params` - @_ExecuteDepositParams. #[inline(always)] -fn execute_deposit_helper(params: @ExecuteDepositParams, _params: @_ExecuteDepositParams) -> u128 { +fn execute_deposit_helper( + params: @ExecuteDepositParams, ref _params: _ExecuteDepositParams +) -> u128 { // for markets where longToken == shortToken, the price impact factor should be set to zero // in which case, the priceImpactUsd would always equal zero let fees = get_swap_fees( *params.data_store, - *_params.market.market_token, - *_params.amount, - *_params.price_impact_usd > 0, - *_params.ui_fee_receiver, + _params.market.market_token, + _params.amount, + _params.price_impact_usd > Zeroable::zero(), + _params.ui_fee_receiver, ); fee_utils::increment_claimable_fee_amount( *params.data_store, *params.event_emitter, - *_params.market.market_token, - *_params.token_in, + _params.market.market_token, + _params.token_in, fees.fee_receiver_amount, deposit_fee_type(), ); @@ -284,35 +283,35 @@ fn execute_deposit_helper(params: @ExecuteDepositParams, _params: @_ExecuteDepos fee_utils::increment_claimable_ui_fee_amount( *params.data_store, *params.event_emitter, - *_params.ui_fee_receiver, - *_params.market.market_token, - *_params.token_in, + _params.ui_fee_receiver, + _params.market.market_token, + _params.token_in, fees.ui_fee_amount, ui_deposit_fee_type(), ); (*params.event_emitter) .emit_swap_fees_collected( - *_params.market.market_token, - *_params.token_in, - *_params.token_in_price.min, + _params.market.market_token, + _params.token_in, + _params.token_in_price.min, 'deposit', fees.clone(), ); let market_pool_value_info = market_utils::get_pool_value_info( *params.data_store, - *_params.market, - (*params.oracle).get_primary_price(*_params.market.index_token), - if *_params.token_in == *_params.market.long_token { - *_params.token_in_price + _params.market, + (*params.oracle).get_primary_price(_params.market.index_token), + if _params.token_in == _params.market.long_token { + _params.token_in_price } else { - *_params.token_out_price + _params.token_out_price }, - if *_params.token_in == *_params.market.short_token { - *_params.token_in_price + if _params.token_in == _params.market.short_token { + _params.token_in_price } else { - *_params.token_out_price + _params.token_out_price }, max_pnl_factor_for_deposits(), true, @@ -324,9 +323,9 @@ fn execute_deposit_helper(params: @ExecuteDepositParams, _params: @_ExecuteDepos ); let mut mint_amount = 0; - let pool_value = market_pool_value_info.pool_value; + let pool_value = to_unsigned(market_pool_value_info.pool_value); let market_tokens_supply = market_utils::get_market_token_supply( - IMarketTokenDispatcher { contract_address: *_params.market.market_token } + IMarketTokenDispatcher { contract_address: _params.market.market_token } ); assert( @@ -336,7 +335,7 @@ fn execute_deposit_helper(params: @ExecuteDepositParams, _params: @_ExecuteDepos (*params.event_emitter) .emit_market_pool_value_info( - *_params.market.market_token, market_pool_value_info, market_tokens_supply, + _params.market.market_token, market_pool_value_info, market_tokens_supply, ); // the pool_value and market_tokens_supply is cached for the mint_amount calculation below @@ -360,15 +359,14 @@ fn execute_deposit_helper(params: @ExecuteDepositParams, _params: @_ExecuteDepos // and again when calculating the mint_amount // // to avoid this, set the price_impact_usd to be zero for this case - let mut price_impact_usd = *_params.price_impact_usd; - if price_impact_usd > 0 && market_tokens_supply == 0 { - price_impact_usd = 0; + if _params.price_impact_usd > Zeroable::zero() && market_tokens_supply == Zeroable::zero() { + _params.price_impact_usd = i128_new(0, false); } let mut amount_after_fees = fees.amount_after_fees; - if price_impact_usd > 0 { + if _params.price_impact_usd > Zeroable::zero() { // when there is a positive price impact factor, // tokens from the swap impact pool are used to mint additional market tokens for the user // for example, if 50,000 USDC is deposited and there is a positive price impact @@ -383,15 +381,14 @@ fn execute_deposit_helper(params: @ExecuteDepositParams, _params: @_ExecuteDepos // it is possible that the addition of the positive impact amount of tokens into the pool // could increase the imbalance of the pool, for most cases this should not be a significant // change compared to the improvement of balance from the actual deposit - let positive_impact_amount = to_unsigned( - market_utils::apply_swap_impact_with_cap( - *params.data_store, - *params.event_emitter, - *_params.market.market_token, - *_params.token_out, - *_params.token_out_price, - to_signed(price_impact_usd, true), - ) + + let positive_impact_amount = market_utils::apply_swap_impact_with_cap( + *params.data_store, + *params.event_emitter, + _params.market.market_token, + _params.token_out, + _params.token_out_price, + _params.price_impact_usd, ); // calculate the usd amount using positiveImpactAmount since it may @@ -406,22 +403,22 @@ fn execute_deposit_helper(params: @ExecuteDepositParams, _params: @_ExecuteDepos // to be zero, in that case, the market token price is also treated as 1 USD mint_amount = market_utils::usd_to_market_token_amount( - positive_impact_amount * *_params.token_out_price.max, - to_unsigned(pool_value), + to_unsigned(positive_impact_amount) * _params.token_out_price.max, + pool_value, market_tokens_supply, ); market_utils::apply_delta_to_pool_amount( *params.data_store, *params.event_emitter, - *_params.market, - *_params.token_out, - to_signed(positive_impact_amount, false), + _params.market, + _params.token_out, + positive_impact_amount ); - market_utils::validate_pool_amount(params.data_store, _params.market, *_params.token_out,); + market_utils::validate_pool_amount(params.data_store, @_params.market, _params.token_out,); - if (price_impact_usd < 0) { + if (_params.price_impact_usd < Zeroable::zero()) { // when there is a negative price impact factor, // less of the deposit amount is used to mint market tokens // for example, if 10 ETH is deposited and there is a negative price impact @@ -430,35 +427,33 @@ fn execute_deposit_helper(params: @ExecuteDepositParams, _params: @_ExecuteDepos let negative_impact_amount = market_utils::apply_swap_impact_with_cap( *params.data_store, *params.event_emitter, - *_params.market.market_token, - *_params.token_out, - *_params.token_out_price, - to_signed(price_impact_usd, false), + _params.market.market_token, + _params.token_out, + _params.token_out_price, + _params.price_impact_usd, ); - amount_after_fees -= to_unsigned((-negative_impact_amount)); + amount_after_fees -= to_unsigned(i128_neg(negative_impact_amount)); } } mint_amount += market_utils::usd_to_market_token_amount( - amount_after_fees * *_params.token_in_price.min, - to_unsigned(pool_value), - market_tokens_supply, + amount_after_fees * _params.token_in_price.min, pool_value, market_tokens_supply, ); market_utils::apply_delta_to_pool_amount( *params.data_store, *params.event_emitter, - *_params.market, - *_params.token_out, - to_signed(amount_after_fees + fees.fee_amount_for_pool, false), + _params.market, + _params.token_out, + to_signed(amount_after_fees + fees.fee_amount_for_pool, true), ); - market_utils::validate_pool_amount(params.data_store, _params.market, *_params.token_in); + market_utils::validate_pool_amount(params.data_store, @_params.market, _params.token_in); - IMarketTokenDispatcher { contract_address: *_params.market.market_token } - .mint(*_params.receiver, mint_amount); + IMarketTokenDispatcher { contract_address: _params.market.market_token } + .mint(_params.receiver, mint_amount); mint_amount } diff --git a/src/market/market_token.cairo b/src/market/market_token.cairo index 110c20fd..31e6e6b0 100644 --- a/src/market/market_token.cairo +++ b/src/market/market_token.cairo @@ -161,7 +161,6 @@ mod MarketToken { let mut bank: Bank::ContractState = Bank::unsafe_new_contract_state(); IBank::transfer_out(ref bank, token, receiver, amount); } - // TODO implement Bank functions } #[external(v0)] diff --git a/src/position/decrease_position_utils.cairo b/src/position/decrease_position_utils.cairo index 1f28a5d3..0b1aff7c 100644 --- a/src/position/decrease_position_utils.cairo +++ b/src/position/decrease_position_utils.cairo @@ -140,7 +140,7 @@ fn decrease_position(mut params: UpdatePositionParams) -> DecreasePositionResult estimated_remaining_collateral_usd += to_signed( params.order.initial_collateral_delta_amount * cache.collateral_token_price.min, - false + true ); params.order.initial_collateral_delta_amount = 0; @@ -156,7 +156,7 @@ fn decrease_position(mut params: UpdatePositionParams) -> DecreasePositionResult if ((estimated_remaining_collateral_usd + cache .estimated_remaining_pnl_usd) < to_signed( - params.contracts.data_store.get_u128(keys::min_collateral_usd()), false + params.contracts.data_store.get_u128(keys::min_collateral_usd()), true )) { params .contracts @@ -275,13 +275,13 @@ fn decrease_position(mut params: UpdatePositionParams) -> DecreasePositionResult params.position.market, params.position.collateral_token, params.position.is_long, - to_signed(cache.initial_collateral_amount - params.position.collateral_amount, true) + to_signed(cache.initial_collateral_amount - params.position.collateral_amount, false) ); position_utils::update_open_interest( params, - to_signed(params.order.size_delta_usd, true), - to_signed(values.size_delta_in_tokens, true) + to_signed(params.order.size_delta_usd, false), + to_signed(values.size_delta_in_tokens, false) ); // affiliate rewards are still distributed even if the order is a liquidation order diff --git a/src/reader/reader_utils.cairo b/src/reader/reader_utils.cairo index 1f77185b..c98b8075 100644 --- a/src/reader/reader_utils.cairo +++ b/src/reader/reader_utils.cairo @@ -208,7 +208,7 @@ fn get_position_info( size_delta_usd = position_info.position.size_in_usd; } - let size_delta_usd_int = calc::to_signed(size_delta_usd, true); + let size_delta_usd_int = calc::to_signed(size_delta_usd, false); position_info .execution_price_result = diff --git a/src/swap/swap_utils.cairo b/src/swap/swap_utils.cairo index e68c87d5..4af3c035 100644 --- a/src/swap/swap_utils.cairo +++ b/src/swap/swap_utils.cairo @@ -284,13 +284,12 @@ fn _swap(params: @SwapParams, _params: @_SwapParams) -> (ContractAddress, u128) .transfer_out(cache.token_out, *_params.receiver, cache.amount_out); } - let mut delta_felt252: felt252 = (cache.amount_in + fees.fee_amount_for_pool).into(); market_utils::apply_delta_to_pool_amount( *params.data_store, *params.event_emitter, *_params.market, *_params.token_in, - delta_felt252.try_into().expect('felt252 into u128 faild'), + calc::to_signed((cache.amount_in + fees.fee_amount_for_pool), true), ); // the poolAmountOut excludes the positive price impact amount