From e217adb188fa4b87fe7a7050fc786615a1cd2481 Mon Sep 17 00:00:00 2001 From: Michal Strug Date: Thu, 12 Dec 2024 22:56:24 +0100 Subject: [PATCH 1/6] Added storing of pre-interactions --- crates/e2e/tests/e2e/quote_verification.rs | 1 + crates/orderbook/src/database/orders.rs | 5 +++ crates/shared/src/order_quoting.rs | 31 +++++++++++++++++-- .../src/price_estimation/trade_verifier.rs | 3 ++ crates/shared/src/trade_finding/external.rs | 1 + crates/shared/src/trade_finding/mod.rs | 1 + 6 files changed, 39 insertions(+), 3 deletions(-) diff --git a/crates/e2e/tests/e2e/quote_verification.rs b/crates/e2e/tests/e2e/quote_verification.rs index 3b50d7ecc3..7d64bc21ea 100644 --- a/crates/e2e/tests/e2e/quote_verification.rs +++ b/crates/e2e/tests/e2e/quote_verification.rs @@ -182,6 +182,7 @@ async fn test_bypass_verification_for_rfq_quotes(web3: Web3) { value: 0.into(), call_data: hex::decode("aa77476c000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599000000000000000000000000000000000000000000000000e357b42c3a9d8ccf0000000000000000000000000000000000000000000000000000000004d0e79e000000000000000000000000a69babef1ca67a37ffaf7a485dfff3382056e78c0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000066360af101ffffffffffffffffffffffffffffffffffffff0f3f47f166360a8d0000003f0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000001c66b3383f287dd9c85ad90e7c5a576ea4ba1bdf5a001d794a9afa379e6b2517b47e487a1aef32e75af432cbdbd301ada42754eaeac21ec4ca744afd92732f47540000000000000000000000000000000000000000000000000000000004d0c80f").unwrap() }], + pre_interactions: vec![], }, }; diff --git a/crates/orderbook/src/database/orders.rs b/crates/orderbook/src/database/orders.rs index 4a1d78fd30..0eade46350 100644 --- a/crates/orderbook/src/database/orders.rs +++ b/crates/orderbook/src/database/orders.rs @@ -1234,6 +1234,11 @@ mod tests { call_data: vec![2, 20], }, ], + pre_interactions: vec![InteractionData { + target: H160([3; 20]), + value: U256::from(30), + call_data: vec![3, 20], + }], } .into(), ..Default::default() diff --git a/crates/shared/src/order_quoting.rs b/crates/shared/src/order_quoting.rs index 6942655449..96ec3a0ea5 100644 --- a/crates/shared/src/order_quoting.rs +++ b/crates/shared/src/order_quoting.rs @@ -447,6 +447,7 @@ impl OrderQuoter { verified: trade_estimate.verified, metadata: QuoteMetadataV1 { interactions: trade_estimate.execution.interactions, + pre_interactions: trade_estimate.execution.pre_interactions, } .into(), }; @@ -690,6 +691,9 @@ impl From for QuoteMetadata { pub struct QuoteMetadataV1 { /// Data provided by the solver in response to /quote request. pub interactions: Vec, + /// The onchain calls to run before sending user funds to the settlement + /// contract. + pub pre_interactions: Vec, } #[cfg(test)] @@ -1643,6 +1647,18 @@ mod tests { call_data: vec![2], }, ], + pre_interactions: vec![ + InteractionData { + target: H160::from([3; 20]), + value: U256::from(3), + call_data: vec![3], + }, + InteractionData { + target: H160::from([4; 20]), + value: U256::from(4), + call_data: vec![4], + }, + ], } .into(); let v = serde_json::to_value(q).unwrap(); @@ -1652,7 +1668,10 @@ mod tests { {"version":"1.0", "interactions":[ {"target":"0x0101010101010101010101010101010101010101","value":"1","callData":"0x01"}, - {"target":"0x0202020202020202020202020202020202020202","value":"2","callData":"0x02"} + {"target":"0x0202020202020202020202020202020202020202","value":"2","callData":"0x02"}], + "preExecutions": + {"target":"0x0303030303030303030303030303030303030303","value":"3","callData":"0x03"}, + {"target":"0x0404040404040404040404040404040404040404","value":"4","callData":"0x04"} ]}"#, ) .unwrap(); @@ -1675,14 +1694,20 @@ mod tests { {"version":"1.0", "interactions":[ {"target":"0x0101010101010101010101010101010101010101","value":"1","callData":"0x01"}, - {"target":"0x0202020202020202020202020202020202020202","value":"2","callData":"0x02"} + {"target":"0x0202020202020202020202020202020202020202","value":"2","callData":"0x02"}], + "preExecutions": + {"target":"0x0303030303030303030303030303030303030303","value":"3","callData":"0x03"}, + {"target":"0x0404040404040404040404040404040404040404","value":"4","callData":"0x04"} ]}"#, ) .unwrap(); let metadata: QuoteMetadata = v1.try_into().unwrap(); match metadata { - QuoteMetadata::V1(v1) => assert_eq!(v1.interactions.len(), 2), + QuoteMetadata::V1(v1) => { + assert_eq!(v1.interactions.len(), 2); + assert_eq!(v1.pre_interactions.len(), 2); + } } } } diff --git a/crates/shared/src/price_estimation/trade_verifier.rs b/crates/shared/src/price_estimation/trade_verifier.rs index 7098695c91..d8ff8cc599 100644 --- a/crates/shared/src/price_estimation/trade_verifier.rs +++ b/crates/shared/src/price_estimation/trade_verifier.rs @@ -220,6 +220,7 @@ impl TradeVerifier { verified: true, execution: QuoteExecution { interactions: map_interactions_data(&trade.interactions()), + pre_interactions: map_interactions_data(&trade.pre_interactions()), }, }; tracing::warn!( @@ -431,6 +432,7 @@ impl TradeVerifying for TradeVerifier { verified: false, execution: QuoteExecution { interactions: map_interactions_data(&trade.interactions()), + pre_interactions: map_interactions_data(&trade.pre_interactions()), }, }; tracing::warn!( @@ -780,6 +782,7 @@ fn ensure_quote_accuracy( verified: true, execution: QuoteExecution { interactions: map_interactions_data(&trade.interactions()), + pre_interactions: map_interactions_data(&trade.pre_interactions()), }, }) } diff --git a/crates/shared/src/trade_finding/external.rs b/crates/shared/src/trade_finding/external.rs index 95e820eb70..b4eae8fd2e 100644 --- a/crates/shared/src/trade_finding/external.rs +++ b/crates/shared/src/trade_finding/external.rs @@ -224,6 +224,7 @@ impl TradeFinding for ExternalTradeFinder { solver: trade.solver(), execution: QuoteExecution { interactions: map_interactions_data(&trade.interactions()), + pre_interactions: map_interactions_data(&trade.pre_interactions()), }, }) } diff --git a/crates/shared/src/trade_finding/mod.rs b/crates/shared/src/trade_finding/mod.rs index 0c0cc9a5ce..740b591eb8 100644 --- a/crates/shared/src/trade_finding/mod.rs +++ b/crates/shared/src/trade_finding/mod.rs @@ -43,6 +43,7 @@ pub struct Quote { #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize)] pub struct QuoteExecution { pub interactions: Vec, + pub pre_interactions: Vec, } #[derive(Clone, Debug, Eq, PartialEq)] From cc259616cd8ec4b7ca3c65043834d5078086b49e Mon Sep 17 00:00:00 2001 From: Michal Strug Date: Thu, 12 Dec 2024 23:19:52 +0100 Subject: [PATCH 2/6] Added storing of jit orders --- crates/e2e/tests/e2e/quote_verification.rs | 1 + crates/orderbook/src/database/orders.rs | 1 + crates/shared/src/order_quoting.rs | 5 +++++ crates/shared/src/price_estimation/trade_verifier.rs | 3 +++ crates/shared/src/trade_finding/external.rs | 5 +++-- crates/shared/src/trade_finding/mod.rs | 8 ++++++++ 6 files changed, 21 insertions(+), 2 deletions(-) diff --git a/crates/e2e/tests/e2e/quote_verification.rs b/crates/e2e/tests/e2e/quote_verification.rs index 7d64bc21ea..3f2dd60fce 100644 --- a/crates/e2e/tests/e2e/quote_verification.rs +++ b/crates/e2e/tests/e2e/quote_verification.rs @@ -183,6 +183,7 @@ async fn test_bypass_verification_for_rfq_quotes(web3: Web3) { call_data: hex::decode("aa77476c000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599000000000000000000000000000000000000000000000000e357b42c3a9d8ccf0000000000000000000000000000000000000000000000000000000004d0e79e000000000000000000000000a69babef1ca67a37ffaf7a485dfff3382056e78c0000000000000000000000009008d19f58aabd9ed0d60971565aa8510560ab41000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000066360af101ffffffffffffffffffffffffffffffffffffff0f3f47f166360a8d0000003f0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000001c66b3383f287dd9c85ad90e7c5a576ea4ba1bdf5a001d794a9afa379e6b2517b47e487a1aef32e75af432cbdbd301ada42754eaeac21ec4ca744afd92732f47540000000000000000000000000000000000000000000000000000000004d0c80f").unwrap() }], pre_interactions: vec![], + jit_orders: vec![], }, }; diff --git a/crates/orderbook/src/database/orders.rs b/crates/orderbook/src/database/orders.rs index 0eade46350..a21884f9c1 100644 --- a/crates/orderbook/src/database/orders.rs +++ b/crates/orderbook/src/database/orders.rs @@ -1239,6 +1239,7 @@ mod tests { value: U256::from(30), call_data: vec![3, 20], }], + jit_orders: vec![], } .into(), ..Default::default() diff --git a/crates/shared/src/order_quoting.rs b/crates/shared/src/order_quoting.rs index 96ec3a0ea5..8730fef829 100644 --- a/crates/shared/src/order_quoting.rs +++ b/crates/shared/src/order_quoting.rs @@ -11,6 +11,7 @@ use { fee::FeeParameters, order_validation::PreOrderData, price_estimation::{Estimate, QuoteVerificationMode, Verification}, + trade_finding::external::dto, }, anyhow::{Context, Result}, chrono::{DateTime, Duration, Utc}, @@ -448,6 +449,7 @@ impl OrderQuoter { metadata: QuoteMetadataV1 { interactions: trade_estimate.execution.interactions, pre_interactions: trade_estimate.execution.pre_interactions, + jit_orders: trade_estimate.execution.jit_orders, } .into(), }; @@ -694,6 +696,8 @@ pub struct QuoteMetadataV1 { /// The onchain calls to run before sending user funds to the settlement /// contract. pub pre_interactions: Vec, + /// Orders that were settled outside of the auction. + pub jit_orders: Vec, } #[cfg(test)] @@ -1659,6 +1663,7 @@ mod tests { call_data: vec![4], }, ], + jit_orders: vec![], } .into(); let v = serde_json::to_value(q).unwrap(); diff --git a/crates/shared/src/price_estimation/trade_verifier.rs b/crates/shared/src/price_estimation/trade_verifier.rs index d8ff8cc599..633938250d 100644 --- a/crates/shared/src/price_estimation/trade_verifier.rs +++ b/crates/shared/src/price_estimation/trade_verifier.rs @@ -221,6 +221,7 @@ impl TradeVerifier { execution: QuoteExecution { interactions: map_interactions_data(&trade.interactions()), pre_interactions: map_interactions_data(&trade.pre_interactions()), + jit_orders: trade.jit_orders(), }, }; tracing::warn!( @@ -433,6 +434,7 @@ impl TradeVerifying for TradeVerifier { execution: QuoteExecution { interactions: map_interactions_data(&trade.interactions()), pre_interactions: map_interactions_data(&trade.pre_interactions()), + jit_orders: trade.jit_orders(), }, }; tracing::warn!( @@ -783,6 +785,7 @@ fn ensure_quote_accuracy( execution: QuoteExecution { interactions: map_interactions_data(&trade.interactions()), pre_interactions: map_interactions_data(&trade.pre_interactions()), + jit_orders: trade.jit_orders(), }, }) } diff --git a/crates/shared/src/trade_finding/external.rs b/crates/shared/src/trade_finding/external.rs index b4eae8fd2e..1ab83f9d0f 100644 --- a/crates/shared/src/trade_finding/external.rs +++ b/crates/shared/src/trade_finding/external.rs @@ -225,6 +225,7 @@ impl TradeFinding for ExternalTradeFinder { execution: QuoteExecution { interactions: map_interactions_data(&trade.interactions()), pre_interactions: map_interactions_data(&trade.pre_interactions()), + jit_orders: trade.jit_orders(), }, }) } @@ -313,7 +314,7 @@ pub(crate) mod dto { } #[serde_as] - #[derive(Clone, Debug, Eq, PartialEq, Deserialize)] + #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] #[allow(unused)] pub struct JitOrder { @@ -346,7 +347,7 @@ pub(crate) mod dto { } #[serde_as] - #[derive(Clone, Debug, Eq, PartialEq, Deserialize)] + #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub enum Side { Buy, diff --git a/crates/shared/src/trade_finding/mod.rs b/crates/shared/src/trade_finding/mod.rs index 740b591eb8..20318b13f7 100644 --- a/crates/shared/src/trade_finding/mod.rs +++ b/crates/shared/src/trade_finding/mod.rs @@ -44,6 +44,7 @@ pub struct Quote { pub struct QuoteExecution { pub interactions: Vec, pub pre_interactions: Vec, + pub jit_orders: Vec, } #[derive(Clone, Debug, Eq, PartialEq)] @@ -108,6 +109,13 @@ impl TradeKind { TradeKind::Regular(trade) => trade.pre_interactions.clone(), } } + + pub fn jit_orders(&self) -> Vec { + match self { + TradeKind::Legacy(_) => Vec::new(), + TradeKind::Regular(trade) => trade.jit_orders.clone(), + } + } } /// A legacy trade. From fc30537206c495674ab1dd6b12b5661b815d230b Mon Sep 17 00:00:00 2001 From: Michal Strug Date: Thu, 12 Dec 2024 23:22:45 +0100 Subject: [PATCH 3/6] Fixed clippy warning --- crates/shared/src/order_quoting.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/shared/src/order_quoting.rs b/crates/shared/src/order_quoting.rs index 8730fef829..a2adf3ddac 100644 --- a/crates/shared/src/order_quoting.rs +++ b/crates/shared/src/order_quoting.rs @@ -245,7 +245,7 @@ pub enum FindQuoteError { NotFound(Option), #[error("quote does not match parameters")] - ParameterMismatch(QuoteData), + ParameterMismatch(Box), #[error("quote expired")] Expired(DateTime), @@ -579,7 +579,7 @@ impl OrderQuoting for OrderQuoter { .ok_or(FindQuoteError::NotFound(Some(id)))?; if !parameters.matches(&data) { - return Err(FindQuoteError::ParameterMismatch(data)); + return Err(FindQuoteError::ParameterMismatch(Box::new(data))); } if data.expiration < now { return Err(FindQuoteError::Expired(data.expiration)); From acb3f43fd3dab1fddd2f98b62e0d5c6fe271ed02 Mon Sep 17 00:00:00 2001 From: Michal Strug Date: Fri, 13 Dec 2024 00:00:42 +0100 Subject: [PATCH 4/6] Fixed tests --- crates/shared/src/order_quoting.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/crates/shared/src/order_quoting.rs b/crates/shared/src/order_quoting.rs index a2adf3ddac..b624f55e51 100644 --- a/crates/shared/src/order_quoting.rs +++ b/crates/shared/src/order_quoting.rs @@ -690,6 +690,7 @@ impl From for QuoteMetadata { } #[derive(Clone, Debug, Default, PartialEq, serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "camelCase")] pub struct QuoteMetadataV1 { /// Data provided by the solver in response to /quote request. pub interactions: Vec, @@ -1674,10 +1675,11 @@ mod tests { "interactions":[ {"target":"0x0101010101010101010101010101010101010101","value":"1","callData":"0x01"}, {"target":"0x0202020202020202020202020202020202020202","value":"2","callData":"0x02"}], - "preExecutions": + "preInteractions":[ {"target":"0x0303030303030303030303030303030303030303","value":"3","callData":"0x03"}, - {"target":"0x0404040404040404040404040404040404040404","value":"4","callData":"0x04"} - ]}"#, + {"target":"0x0404040404040404040404040404040404040404","value":"4","callData":"0x04"}], + "jitOrders":[] + }"#, ) .unwrap(); @@ -1700,10 +1702,11 @@ mod tests { "interactions":[ {"target":"0x0101010101010101010101010101010101010101","value":"1","callData":"0x01"}, {"target":"0x0202020202020202020202020202020202020202","value":"2","callData":"0x02"}], - "preExecutions": + "preInteractions":[ {"target":"0x0303030303030303030303030303030303030303","value":"3","callData":"0x03"}, - {"target":"0x0404040404040404040404040404040404040404","value":"4","callData":"0x04"} - ]}"#, + {"target":"0x0404040404040404040404040404040404040404","value":"4","callData":"0x04"}], + "jitOrders":[] + }"#, ) .unwrap(); let metadata: QuoteMetadata = v1.try_into().unwrap(); @@ -1712,6 +1715,7 @@ mod tests { QuoteMetadata::V1(v1) => { assert_eq!(v1.interactions.len(), 2); assert_eq!(v1.pre_interactions.len(), 2); + assert!(v1.jit_orders.is_empty()); } } } From 57b49a498322e7c1bbe8b2716122fe23abd10c3a Mon Sep 17 00:00:00 2001 From: Michal Strug Date: Fri, 13 Dec 2024 11:10:43 +0100 Subject: [PATCH 5/6] Updated test --- crates/shared/src/order_quoting.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/crates/shared/src/order_quoting.rs b/crates/shared/src/order_quoting.rs index b624f55e51..d2947a6219 100644 --- a/crates/shared/src/order_quoting.rs +++ b/crates/shared/src/order_quoting.rs @@ -1664,7 +1664,22 @@ mod tests { call_data: vec![4], }, ], - jit_orders: vec![], + jit_orders: vec![dto::JitOrder { + buy_token: H160([4; 20]), + sell_token: H160([5; 20]), + sell_amount: U256::from(10), + buy_amount: U256::from(20), + executed_amount: U256::from(11), + receiver: H160([6; 20]), + valid_to: 1734084318, + app_data: Default::default(), + side: dto::Side::Sell, + partially_fillable: false, + sell_token_source: model::order::SellTokenSource::External, + buy_token_destination: model::order::BuyTokenDestination::Internal, + signature: vec![1; 16], + signing_scheme: model::signature::SigningScheme::Eip712, + }], } .into(); let v = serde_json::to_value(q).unwrap(); @@ -1678,7 +1693,11 @@ mod tests { "preInteractions":[ {"target":"0x0303030303030303030303030303030303030303","value":"3","callData":"0x03"}, {"target":"0x0404040404040404040404040404040404040404","value":"4","callData":"0x04"}], - "jitOrders":[] + "jitOrders":[{"appData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "buyAmount": "20", "buyToken": "0x0404040404040404040404040404040404040404", "buyTokenDestination": "internal", + "executedAmount": "11", "partiallyFillable": false, "receiver": "0x0606060606060606060606060606060606060606", + "sellAmount": "10", "sellToken": "0x0505050505050505050505050505050505050505", "sellTokenSource": "external", + "side": "sell", "signature": "0x01010101010101010101010101010101", "signingScheme": "eip712", "validTo": 1734084318}] }"#, ) .unwrap(); From 295426e94c6daa0b3ae9eeb74040f69c264c59bf Mon Sep 17 00:00:00 2001 From: Michal Strug Date: Fri, 13 Dec 2024 14:48:58 +0100 Subject: [PATCH 6/6] Updated test --- crates/shared/src/order_quoting.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/crates/shared/src/order_quoting.rs b/crates/shared/src/order_quoting.rs index d2947a6219..60a78a141b 100644 --- a/crates/shared/src/order_quoting.rs +++ b/crates/shared/src/order_quoting.rs @@ -1724,7 +1724,16 @@ mod tests { "preInteractions":[ {"target":"0x0303030303030303030303030303030303030303","value":"3","callData":"0x03"}, {"target":"0x0404040404040404040404040404040404040404","value":"4","callData":"0x04"}], - "jitOrders":[] + "jitOrders":[{"appData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "buyAmount": "20", "buyToken": "0x0404040404040404040404040404040404040404", "buyTokenDestination": "internal", + "executedAmount": "11", "partiallyFillable": false, "receiver": "0x0606060606060606060606060606060606060606", + "sellAmount": "10", "sellToken": "0x0505050505050505050505050505050505050505", "sellTokenSource": "external", + "side": "sell", "signature": "0x01010101010101010101010101010101", "signingScheme": "eip712", "validTo": 1734084318}, + {"appData": "0x0ddeb6e4a814908832cc25d11311c514e7efe6af3c9bafeb0d241129cf7f4d83", + "buyAmount": "100", "buyToken": "0x0606060606060606060606060606060606060606", "buyTokenDestination": "erc20", + "executedAmount": "99", "partiallyFillable": true, "receiver": "0x0303030303030303030303030303030303030303", + "sellAmount": "10", "sellToken": "0x0101010101010101010101010101010101010101", "sellTokenSource": "erc20", + "side": "buy", "signature": "0x01010101010101010101010101010101", "signingScheme": "eip1271", "validTo": 1734085109}] }"#, ) .unwrap(); @@ -1734,7 +1743,7 @@ mod tests { QuoteMetadata::V1(v1) => { assert_eq!(v1.interactions.len(), 2); assert_eq!(v1.pre_interactions.len(), 2); - assert!(v1.jit_orders.is_empty()); + assert_eq!(v1.jit_orders.len(), 2); } } }