Skip to content
Merged
160 changes: 159 additions & 1 deletion crates/e2e/tests/e2e/place_order_with_quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ use {
configs::{
autopilot::Configuration,
order_quoting::{ExternalSolver, OrderQuoting},
orderbook::order_validation::{OrderValidationConfig, SameTokensPolicy},
shared::SharedConfig,
test_util::TestDefault,
},
e2e::setup::{colocation, wait_for_condition, *},
ethrpc::alloy::{CallBuilderExt, EvmProviderExt},
model::{
order::{OrderCreation, OrderKind},
order::{BUY_ETH_ADDRESS, OrderCreation, OrderKind},
quote::{OrderQuoteRequest, OrderQuoteSide, SellAmount},
signature::EcdsaSigningScheme,
},
Expand All @@ -37,6 +38,18 @@ async fn local_node_fallback_native_price_estimator() {
run_test(fallback_native_price_estimator).await;
}

#[tokio::test]
#[ignore]
async fn local_node_native_same_token_sell_with_eth_buy_marker() {
run_test(native_same_token_sell_with_eth_buy_marker).await;
}

#[tokio::test]
#[ignore]
async fn local_node_native_same_token_buy_with_eth_buy_marker_rejected() {
run_test(native_same_token_buy_with_eth_buy_marker_rejected).await;
}
Comment thread
m-sz marked this conversation as resolved.
Outdated

async fn place_order_with_quote(web3: Web3) {
let mut onchain = OnchainComponents::deploy(web3.clone()).await;

Expand Down Expand Up @@ -175,6 +188,151 @@ async fn disabled_same_sell_and_buy_token_order_feature(web3: Web3) {
);
}

async fn native_same_token_sell_with_eth_buy_marker(web3: Web3) {
let mut onchain = OnchainComponents::deploy(web3.clone()).await;

let [solver] = onchain.make_solvers(10u64.eth()).await;
let [trader] = onchain.make_accounts(10u64.eth()).await;

onchain
.contracts()
.weth
.approve(onchain.contracts().allowance, 3u64.eth())
.from(trader.address())
.send_and_watch()
.await
.unwrap();
onchain
.contracts()
.weth
.deposit()
.from(trader.address())
.value(3u64.eth())
.send_and_watch()
.await
.unwrap();

tracing::info!("Starting services.");
let services = Services::new(&onchain).await;
let orderbook_config = configs::orderbook::Configuration {
order_validation: OrderValidationConfig {
same_tokens_policy: SameTokensPolicy::AllowSell,
..Default::default()
},
..configs::orderbook::Configuration::test_default()
};
services
.start_protocol_with_args(
Default::default(),
Configuration::test("test_solver", solver.address()),
orderbook_config,
solver.clone(),
)
.await;

web3.provider
.evm_set_automine(false)
.await
.expect("Must be able to disable automine");

let quote_sell_amount = 1u64.eth();
let quote_request = OrderQuoteRequest {
from: trader.address(),
sell_token: *onchain.contracts().weth.address(),
buy_token: BUY_ETH_ADDRESS,
side: OrderQuoteSide::Sell {
sell_amount: SellAmount::BeforeFee {
value: NonZeroU256::try_from(quote_sell_amount).unwrap(),
},
},
..Default::default()
};

let quote_response = services.submit_quote(&quote_request).await.unwrap();
assert!(quote_response.verified);
assert!(quote_response.id.is_some());

let order = OrderCreation {
quote_id: quote_response.id,
sell_token: *onchain.contracts().weth.address(),
sell_amount: quote_sell_amount,
buy_token: BUY_ETH_ADDRESS,
buy_amount: quote_response.quote.buy_amount,
valid_to: model::time::now_in_epoch_seconds() + 300,
kind: OrderKind::Sell,
..Default::default()
}
.sign(
EcdsaSigningScheme::Eip712,
&onchain.contracts().domain_separator,
&trader.signer,
);

services.create_order(&order).await.unwrap();
Comment thread
m-sz marked this conversation as resolved.
Outdated
}

async fn native_same_token_buy_with_eth_buy_marker_rejected(web3: Web3) {
let mut onchain = OnchainComponents::deploy(web3.clone()).await;

let [solver] = onchain.make_solvers(10u64.eth()).await;
let [trader] = onchain.make_accounts(10u64.eth()).await;

onchain
.contracts()
.weth
.approve(onchain.contracts().allowance, 3u64.eth())
.from(trader.address())
.send_and_watch()
.await
.unwrap();
onchain
.contracts()
.weth
.deposit()
.from(trader.address())
.value(3u64.eth())
.send_and_watch()
.await
.unwrap();

tracing::info!("Starting services.");
let services = Services::new(&onchain).await;
let orderbook_config = configs::orderbook::Configuration {
order_validation: OrderValidationConfig {
same_tokens_policy: SameTokensPolicy::AllowSell,
..Default::default()
},
..configs::orderbook::Configuration::test_default()
};
services
.start_protocol_with_args(
Default::default(),
Configuration::test("test_solver", solver.address()),
orderbook_config,
solver.clone(),
)
.await;

web3.provider
.evm_set_automine(false)
.await
.expect("Must be able to disable automine");

let quote_request = OrderQuoteRequest {
from: trader.address(),
sell_token: *onchain.contracts().weth.address(),
buy_token: BUY_ETH_ADDRESS,
side: OrderQuoteSide::Buy {
buy_amount_after_fee: NonZeroU256::try_from(1u64.eth()).unwrap(),
},
..Default::default()
};

assert!(
matches!(services.submit_quote(&quote_request).await, Err((reqwest::StatusCode::BAD_REQUEST, response)) if response.contains("SameBuyAndSellToken"))
);
Comment thread
jmg-duarte marked this conversation as resolved.
Outdated
}

async fn fallback_native_price_estimator(web3: Web3) {
let mut onchain = OnchainComponents::deploy(web3.clone()).await;

Expand Down
49 changes: 44 additions & 5 deletions crates/shared/src/order_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,12 +217,10 @@ fn validate_same_sell_and_buy_token(
order: &PreOrderData,
native_token: &Address,
) -> Result<(), PartialValidationError> {
// Check for orders selling wrapped native token for native token.
if &order.sell_token == native_token && order.buy_token == BUY_ETH_ADDRESS {
return Err(PartialValidationError::SameBuyAndSellToken);
}
let same_token = order.sell_token == order.buy_token
|| (&order.sell_token == native_token && order.buy_token == BUY_ETH_ADDRESS);

if order.sell_token != order.buy_token {
if !same_token {
return Ok(());
}

Expand Down Expand Up @@ -1075,6 +1073,7 @@ mod tests {
#[tokio::test]
async fn pre_validate_err() {
let native_token = WETH9::Instance::new([0xef; 20].into(), ethrpc::mock::web3().provider);
let native_token_address = *native_token.address();
let validity_configuration = OrderValidPeriodConfiguration {
min: Duration::from_secs(1),
max_market: Duration::from_secs(100),
Expand Down Expand Up @@ -1206,6 +1205,17 @@ mod tests {
.await,
Err(PartialValidationError::SameBuyAndSellToken)
));
assert!(matches!(
validator
.partial_validate(PreOrderData {
valid_to: legit_valid_to,
buy_token: BUY_ETH_ADDRESS,
sell_token: native_token_address,
..Default::default()
})
.await,
Err(PartialValidationError::SameBuyAndSellToken)
));
assert!(matches!(
validator
.partial_validate(PreOrderData {
Expand Down Expand Up @@ -1366,6 +1376,35 @@ mod tests {
)
.is_ok()
);

let native_order = || PreOrderData {
buy_token: BUY_ETH_ADDRESS,
sell_token: *native_token.address(),
valid_to: time::now_in_epoch_seconds()
+ validity_configuration.min.as_secs() as u32
+ 2,
..Default::default()
};

assert!(matches!(
validator
.partial_validate(PreOrderData {
kind: OrderKind::Buy,
..native_order()
})
.await,
Err(PartialValidationError::SameBuyAndSellToken)
));

assert!(
validator
.partial_validate(PreOrderData {
kind: OrderKind::Sell,
..native_order()
})
.await
.is_ok()
);
}

#[tokio::test]
Expand Down
Loading