-
Notifications
You must be signed in to change notification settings - Fork 110
feat(tpu): provide premium for tpu #2405
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
base: dev
Are you sure you want to change the base?
Changes from 18 commits
aee2d17
1736774
810addf
2d996d1
9eb0663
419d91a
4f1002c
cd53b6d
1344166
99c7d41
c3217ae
af2c3c5
18dc713
4aaf0bd
96594e1
7d2f22c
011798a
e19e1c5
385b382
285b9ef
74c126d
1332c21
0207b02
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1639,7 +1639,22 @@ impl TakerOrder { | |
| || self.base_orderbook_ticker.as_ref() == Some(&reserved.rel)) | ||
| && (self.request.rel == reserved.base | ||
| || self.rel_orderbook_ticker.as_ref() == Some(&reserved.base)); | ||
| if match_ticker && my_base_amount == other_rel_amount && my_rel_amount <= other_base_amount { | ||
|
|
||
| // Reject if any common conditions are unmet | ||
| if !match_ticker || my_base_amount != other_rel_amount { | ||
| return MatchReservedResult::NotMatched; | ||
| } | ||
|
|
||
| let other_base_amount = if self.request.swap_version.is_legacy() || reserved.swap_version.is_legacy() { | ||
| other_base_amount.clone() | ||
| } else { | ||
| let premium = &reserved.premium.clone().unwrap_or_default(); | ||
| let other_price = &(my_base_amount - premium) / other_base_amount; | ||
| // In match_with_request function, we allowed maker to send fewer coins for taker sell action | ||
| other_base_amount + &(premium / &other_price) | ||
| }; | ||
|
|
||
| if my_rel_amount <= &other_base_amount { | ||
| MatchReservedResult::Matched | ||
| } else { | ||
| MatchReservedResult::NotMatched | ||
|
|
@@ -1722,6 +1737,8 @@ pub struct MakerOrder { | |
| p2p_privkey: Option<SerializableSecp256k1Keypair>, | ||
| #[serde(default, skip_serializing_if = "SwapVersion::is_legacy")] | ||
| pub swap_version: SwapVersion, | ||
| #[serde(default, skip_serializing_if = "Option::is_none")] | ||
| premium: Option<MmNumber>, | ||
| } | ||
|
|
||
| pub struct MakerOrderBuilder<'a> { | ||
|
|
@@ -1735,6 +1752,7 @@ pub struct MakerOrderBuilder<'a> { | |
| conf_settings: Option<OrderConfirmationsSettings>, | ||
| save_in_history: bool, | ||
| swap_version: u8, | ||
| premium: Option<MmNumber>, | ||
borngraced marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| pub enum MakerOrderBuildError { | ||
|
|
@@ -1885,6 +1903,7 @@ impl<'a> MakerOrderBuilder<'a> { | |
| conf_settings: None, | ||
| save_in_history: true, | ||
| swap_version: SWAP_VERSION_DEFAULT, | ||
| premium: Default::default(), | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -1929,6 +1948,11 @@ impl<'a> MakerOrderBuilder<'a> { | |
| /// In the future alls users will be using TPU V2 by default without "use_trading_proto_v2" configuration. | ||
| pub fn set_legacy_swap_v(&mut self) { self.swap_version = legacy_swap_version() } | ||
|
|
||
| pub fn with_premium(mut self, premium: Option<MmNumber>) -> Self { | ||
| self.premium = premium; | ||
| self | ||
| } | ||
|
|
||
| /// Build MakerOrder | ||
| #[allow(clippy::result_large_err)] | ||
| pub fn build(self) -> Result<MakerOrder, MakerOrderBuildError> { | ||
|
|
@@ -1986,6 +2010,7 @@ impl<'a> MakerOrderBuilder<'a> { | |
| rel_orderbook_ticker: self.rel_orderbook_ticker, | ||
| p2p_privkey, | ||
| swap_version: SwapVersion::from(self.swap_version), | ||
| premium: self.premium, | ||
| }) | ||
| } | ||
|
|
||
|
|
@@ -2011,6 +2036,7 @@ impl<'a> MakerOrderBuilder<'a> { | |
| rel_orderbook_ticker: None, | ||
| p2p_privkey: None, | ||
| swap_version: SwapVersion::from(self.swap_version), | ||
| premium: Default::default(), | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -2049,31 +2075,66 @@ impl MakerOrder { | |
| return OrderMatchResult::NotMatched; | ||
| } | ||
|
|
||
| let is_legacy = self.swap_version.is_legacy() || taker.swap_version.is_legacy(); | ||
|
|
||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: we may get premium as reference here, like: and use it within |
||
| match taker.action { | ||
| TakerAction::Buy => { | ||
| let ticker_match = (self.base == taker.base | ||
| || self.base_orderbook_ticker.as_ref() == Some(&taker.base)) | ||
| && (self.rel == taker.rel || self.rel_orderbook_ticker.as_ref() == Some(&taker.rel)); | ||
| // taker_base_amount: the amount taker desires to buy (input.volume from SellBuyRequest) | ||
| // taker_rel_amount: the amount taker is willing to pay (input.volume * input.price, where input is SellBuyRequest) | ||
| // taker_price: the effective price offered by the taker | ||
| let taker_price = taker_rel_amount / taker_base_amount; | ||
| if ticker_match | ||
| && taker_base_amount <= &self.available_amount() | ||
| && taker_base_amount >= &self.min_base_vol | ||
| && taker_price >= self.price | ||
| { | ||
|
|
||
| // Reject if any basic conditions are not satisfied | ||
| let base_amount_exceeds = taker_base_amount > &self.available_amount(); | ||
| let below_min_volume = taker_base_amount < &self.min_base_vol; | ||
| let price_too_low = taker_price < self.price; | ||
|
|
||
| if !ticker_match || base_amount_exceeds || below_min_volume || price_too_low { | ||
| return OrderMatchResult::NotMatched; | ||
| } | ||
|
|
||
| if is_legacy { | ||
| // Legacy mode: use maker's price to calculate rel amount | ||
| OrderMatchResult::Matched((taker_base_amount.clone(), taker_base_amount * &self.price)) | ||
| } else { | ||
| OrderMatchResult::NotMatched | ||
| // taker_rel_amount must cover the premium requested by maker | ||
| let required_rel_amount = | ||
| taker_base_amount * &self.price + self.premium.clone().unwrap_or_default(); | ||
|
||
| if taker_rel_amount >= &required_rel_amount { | ||
| // TPU mode: treat buy as a limit order using taker's base and rel amounts | ||
| OrderMatchResult::Matched((taker_base_amount.clone(), taker_rel_amount.clone())) | ||
| } else { | ||
| OrderMatchResult::NotMatched | ||
| } | ||
| } | ||
| }, | ||
| TakerAction::Sell => { | ||
| let ticker_match = (self.base == taker.rel || self.base_orderbook_ticker.as_ref() == Some(&taker.rel)) | ||
| && (self.rel == taker.base || self.rel_orderbook_ticker.as_ref() == Some(&taker.base)); | ||
| let taker_price = taker_base_amount / taker_rel_amount; | ||
| let premium = self.premium.clone().unwrap_or_default(); | ||
|
|
||
| // Calculate the resulting base amount using the Maker's price instead of the Taker's. | ||
| let matched_base_amount = taker_base_amount / &self.price; | ||
| let matched_rel_amount = taker_base_amount.clone(); | ||
| // Determine the matched amounts depending on version | ||
| let (matched_base_amount, matched_rel_amount) = if is_legacy { | ||
| // Legacy: calculate the resulting base amount using the Maker's price instead of the Taker's. | ||
| (taker_base_amount / &self.price, taker_base_amount.clone()) | ||
| } else { | ||
| // For TPU, if the total rel amount from the taker (rel is coin which should be sent by taker during swap) | ||
| // is less than or equal to the maker's premium, the trade is not possible | ||
| if taker_base_amount <= &premium { | ||
| return OrderMatchResult::NotMatched; | ||
| } | ||
| // Calculate the resulting base amount using the maker's price instead of the taker's. | ||
| // The maker wants to "take" an additional portion of rel as a premium, | ||
| // so we reduce the base amount the maker gives by (premium / price). | ||
| let matched_base_amount = &(taker_base_amount - &premium) / &self.price; | ||
dimxy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| (matched_base_amount, taker_base_amount.clone()) | ||
| }; | ||
|
|
||
| // Match if all common conditions are met | ||
| if ticker_match | ||
| && matched_base_amount <= self.available_amount() | ||
dimxy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| && matched_base_amount >= self.min_base_vol | ||
|
|
@@ -2142,6 +2203,7 @@ impl From<TakerOrder> for MakerOrder { | |
| rel_orderbook_ticker: taker_order.rel_orderbook_ticker, | ||
| p2p_privkey: taker_order.p2p_privkey, | ||
| swap_version: taker_order.request.swap_version, | ||
| premium: Default::default(), | ||
| }, | ||
| // The "buy" taker order is recreated with reversed pair as Maker order is always considered as "sell" | ||
| TakerAction::Buy => { | ||
|
|
@@ -2165,6 +2227,7 @@ impl From<TakerOrder> for MakerOrder { | |
| rel_orderbook_ticker: taker_order.base_orderbook_ticker, | ||
| p2p_privkey: taker_order.p2p_privkey, | ||
| swap_version: taker_order.request.swap_version, | ||
| premium: Default::default(), | ||
| } | ||
| }, | ||
| } | ||
|
|
@@ -2217,6 +2280,11 @@ pub struct MakerReserved { | |
| pub rel_protocol_info: Option<Vec<u8>>, | ||
| #[serde(default, skip_serializing_if = "SwapVersion::is_legacy")] | ||
| pub swap_version: SwapVersion, | ||
| /// Note: `std::default::Default` is not implemented for `num_rational::Ratio<mm2_number::BigInt>` | ||
| /// in the [new_protocol::MakerReserved] structure. As a result, we use `Option<BigRational>` there. | ||
| /// It is preferable to follow this same approach in the current structure for consistency. | ||
| #[serde(default, skip_serializing_if = "Option::is_none")] | ||
| premium: Option<MmNumber>, | ||
borngraced marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| impl MakerReserved { | ||
|
|
@@ -2245,6 +2313,7 @@ impl MakerReserved { | |
| base_protocol_info: message.base_protocol_info, | ||
| rel_protocol_info: message.rel_protocol_info, | ||
| swap_version: message.swap_version, | ||
| premium: message.premium.map(MmNumber::from), | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -2262,6 +2331,7 @@ impl From<MakerReserved> for new_protocol::OrdermatchMessage { | |
| base_protocol_info: maker_reserved.base_protocol_info, | ||
| rel_protocol_info: maker_reserved.rel_protocol_info, | ||
| swap_version: maker_reserved.swap_version, | ||
| premium: maker_reserved.premium.map(|p| p.to_ratio()), | ||
| }) | ||
| } | ||
| } | ||
|
|
@@ -2998,6 +3068,7 @@ struct StateMachineParams<'a> { | |
| locktime: &'a u64, | ||
| maker_amount: &'a MmNumber, | ||
| taker_amount: &'a MmNumber, | ||
| taker_premium: &'a MmNumber, | ||
| } | ||
|
|
||
| #[cfg_attr(test, mockable)] | ||
|
|
@@ -3110,6 +3181,7 @@ fn lp_connect_start_bob(ctx: MmArc, maker_match: MakerMatch, maker_order: MakerO | |
| locktime: &lock_time, | ||
| maker_amount: &maker_amount, | ||
| taker_amount: &taker_amount, | ||
| taker_premium: &maker_order.premium.clone().unwrap_or_default(), | ||
| }; | ||
| let taker_p2p_pubkey = match taker_p2p_pubkey { | ||
| PublicKey::Secp256k1(pubkey) => pubkey.into(), | ||
|
|
@@ -3212,7 +3284,7 @@ async fn start_maker_swap_state_machine< | |
| secret: *secret, | ||
| taker_coin: taker_coin.clone(), | ||
| taker_volume: params.taker_amount.clone(), | ||
| taker_premium: Default::default(), | ||
| taker_premium: params.taker_premium.clone(), | ||
| conf_settings: *params.my_conf_settings, | ||
| p2p_topic: swap_v2_topic(params.uuid), | ||
| uuid: *params.uuid, | ||
|
|
@@ -3342,6 +3414,7 @@ fn lp_connected_alice(ctx: MmArc, taker_order: TakerOrder, taker_match: TakerMat | |
| locktime: &locktime, | ||
| maker_amount: &maker_amount, | ||
| taker_amount: &taker_amount, | ||
| taker_premium: &taker_match.reserved.premium.unwrap_or_default(), | ||
| }; | ||
| let maker_p2p_pubkey = match maker_p2p_pubkey { | ||
| PublicKey::Secp256k1(pubkey) => pubkey.into(), | ||
|
|
@@ -3451,7 +3524,7 @@ async fn start_taker_swap_state_machine< | |
| maker_volume: params.maker_amount.clone(), | ||
| taker_coin: taker_coin.clone(), | ||
| taker_volume: params.taker_amount.clone(), | ||
| taker_premium: Default::default(), | ||
| taker_premium: params.taker_premium.clone(), | ||
| secret_hash_algo: *params.secret_hash_algo, | ||
| conf_settings: *params.my_conf_settings, | ||
| p2p_topic: swap_v2_topic(params.uuid), | ||
|
|
@@ -3983,6 +4056,7 @@ async fn process_taker_request(ctx: MmArc, from_pubkey: H256Json, taker_request: | |
| base_protocol_info: Some(base_coin.coin_protocol_info(None)), | ||
| rel_protocol_info: Some(rel_coin.coin_protocol_info(Some(rel_amount.clone()))), | ||
| swap_version: order.swap_version, | ||
| premium: order.premium.clone(), | ||
| }; | ||
| let topic = order.orderbook_topic(); | ||
| log::debug!("Request matched sending reserved {:?}", reserved); | ||
|
|
@@ -4711,6 +4785,8 @@ pub struct SetPriceReq { | |
| rel_nota: Option<bool>, | ||
| #[serde(default = "get_true")] | ||
| save_in_history: bool, | ||
| #[serde(default)] | ||
| premium: Option<MmNumber>, | ||
| } | ||
|
|
||
| #[derive(Deserialize)] | ||
|
|
@@ -4978,7 +5054,8 @@ pub async fn create_maker_order(ctx: &MmArc, req: SetPriceReq) -> Result<MakerOr | |
| .with_conf_settings(conf_settings) | ||
| .with_save_in_history(req.save_in_history) | ||
| .with_base_orderbook_ticker(ordermatch_ctx.orderbook_ticker(base_coin.ticker())) | ||
| .with_rel_orderbook_ticker(ordermatch_ctx.orderbook_ticker(rel_coin.ticker())); | ||
| .with_rel_orderbook_ticker(ordermatch_ctx.orderbook_ticker(rel_coin.ticker())) | ||
| .with_premium(req.premium); | ||
dimxy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if !ctx.use_trading_proto_v2() { | ||
| builder.set_legacy_swap_v(); | ||
| } | ||
|
|
@@ -5195,7 +5272,7 @@ pub async fn update_maker_order_rpc(ctx: MmArc, req: Json) -> Result<Response<Ve | |
| /// Result of match_order_and_request function | ||
| #[derive(Debug, PartialEq)] | ||
| enum OrderMatchResult { | ||
| /// Order and request matched, contains base and rel resulting amounts | ||
| /// Order and request matched, contains base and rel resulting amounts (represent maker and taker payment amounts for swap) | ||
| Matched((MmNumber, MmNumber)), | ||
| /// Orders didn't match | ||
| NotMatched, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not add a doc comment for this field?