@@ -19,10 +19,28 @@ use {
1919
2020#[ tokio:: test]
2121#[ ignore]
22- async fn local_node_test ( ) {
22+ async fn local_node_on_expiry ( ) {
2323 run_test ( test_cancel_on_expiry) . await ;
2424}
2525
26+ #[ tokio:: test]
27+ #[ ignore]
28+ async fn local_node_execute_same_sell_and_buy_token ( ) {
29+ run_test ( test_execute_same_sell_and_buy_token) . await ;
30+ }
31+
32+ #[ tokio:: test]
33+ #[ ignore]
34+ async fn local_node_submit_same_sell_and_buy_token_order_without_quote ( ) {
35+ run_test ( test_submit_same_sell_and_buy_token_order_without_quote) . await ;
36+ }
37+
38+ #[ tokio:: test]
39+ #[ ignore]
40+ async fn local_node_submit_same_sell_and_buy_token_order_without_quote_fail ( ) {
41+ run_test ( test_submit_same_sell_and_buy_token_order_without_quote_fail) . await ;
42+ }
43+
2644async fn test_cancel_on_expiry ( web3 : Web3 ) {
2745 let mut onchain = OnchainComponents :: deploy ( web3. clone ( ) ) . await ;
2846
@@ -123,6 +141,222 @@ async fn test_cancel_on_expiry(web3: Web3) {
123141 assert_eq ! ( tx. to, Some ( solver. account( ) . address( ) ) )
124142}
125143
144+ async fn test_submit_same_sell_and_buy_token_order_without_quote ( web3 : Web3 ) {
145+ let mut onchain = OnchainComponents :: deploy ( web3. clone ( ) ) . await ;
146+
147+ let [ solver] = onchain. make_solvers ( eth ( 10 ) ) . await ;
148+ let [ trader] = onchain. make_accounts ( eth ( 10 ) ) . await ;
149+ let [ token] = onchain
150+ . deploy_tokens_with_weth_uni_v2_pools ( to_wei ( 1_000 ) , to_wei ( 1_000 ) )
151+ . await ;
152+
153+ token. mint ( trader. address ( ) , eth ( 10 ) ) . await ;
154+
155+ token
156+ . approve ( onchain. contracts ( ) . allowance . into_alloy ( ) , eth ( 10 ) )
157+ . from ( trader. address ( ) )
158+ . send_and_watch ( )
159+ . await
160+ . unwrap ( ) ;
161+
162+ tracing:: info!( "Starting services." ) ;
163+ let services = Services :: new ( & onchain) . await ;
164+ services
165+ . start_protocol_with_args (
166+ ExtraServiceArgs {
167+ api : vec ! [ "--allow-same-sell-and-buy-token=true" . to_string( ) ] ,
168+ ..Default :: default ( )
169+ } ,
170+ solver. clone ( ) ,
171+ )
172+ . await ;
173+
174+ // Disable auto-mine so we don't accidentally mine a settlement
175+ web3. api :: < TestNodeApi < _ > > ( )
176+ . set_automine_enabled ( false )
177+ . await
178+ . expect ( "Must be able to disable automine" ) ;
179+
180+ tracing:: info!( "Placing order" ) ;
181+ let order = OrderCreation {
182+ sell_token : token. address ( ) . into_legacy ( ) ,
183+ sell_amount : to_wei ( 1 ) ,
184+ buy_token : token. address ( ) . into_legacy ( ) ,
185+ buy_amount : to_wei ( 1 ) ,
186+ valid_to : model:: time:: now_in_epoch_seconds ( ) + 300 ,
187+ kind : OrderKind :: Sell ,
188+ ..Default :: default ( )
189+ }
190+ . sign (
191+ EcdsaSigningScheme :: Eip712 ,
192+ & onchain. contracts ( ) . domain_separator ,
193+ SecretKeyRef :: from ( & SecretKey :: from_slice ( trader. private_key ( ) ) . unwrap ( ) ) ,
194+ ) ;
195+ services. create_order ( & order) . await . unwrap ( ) ;
196+ }
197+
198+ async fn test_submit_same_sell_and_buy_token_order_without_quote_fail ( web3 : Web3 ) {
199+ let mut onchain = OnchainComponents :: deploy ( web3. clone ( ) ) . await ;
200+
201+ let [ solver] = onchain. make_solvers ( eth ( 10 ) ) . await ;
202+ let [ trader] = onchain. make_accounts ( eth ( 10 ) ) . await ;
203+ let [ token] = onchain
204+ . deploy_tokens_with_weth_uni_v2_pools ( to_wei ( 1_000 ) , to_wei ( 1_000 ) )
205+ . await ;
206+
207+ token. mint ( trader. address ( ) , eth ( 10 ) ) . await ;
208+
209+ token
210+ . approve ( onchain. contracts ( ) . allowance . into_alloy ( ) , eth ( 10 ) )
211+ . from ( trader. address ( ) )
212+ . send_and_watch ( )
213+ . await
214+ . unwrap ( ) ;
215+
216+ tracing:: info!( "Starting services." ) ;
217+ let services = Services :: new ( & onchain) . await ;
218+ services. start_protocol ( solver. clone ( ) ) . await ;
219+
220+ // Disable auto-mine so we don't accidentally mine a settlement
221+ web3. api :: < TestNodeApi < _ > > ( )
222+ . set_automine_enabled ( false )
223+ . await
224+ . expect ( "Must be able to disable automine" ) ;
225+
226+ tracing:: info!( "Placing order" ) ;
227+ let order = OrderCreation {
228+ sell_token : token. address ( ) . into_legacy ( ) ,
229+ sell_amount : to_wei ( 1 ) ,
230+ buy_token : token. address ( ) . into_legacy ( ) ,
231+ buy_amount : to_wei ( 1 ) ,
232+ valid_to : model:: time:: now_in_epoch_seconds ( ) + 300 ,
233+ kind : OrderKind :: Sell ,
234+ ..Default :: default ( )
235+ }
236+ . sign (
237+ EcdsaSigningScheme :: Eip712 ,
238+ & onchain. contracts ( ) . domain_separator ,
239+ SecretKeyRef :: from ( & SecretKey :: from_slice ( trader. private_key ( ) ) . unwrap ( ) ) ,
240+ ) ;
241+ // services.create_order(&order).await.unwrap();
242+ assert ! (
243+ matches!( services. create_order( & order) . await , Err ( ( reqwest:: StatusCode :: BAD_REQUEST , response) ) if response. contains( "SameBuyAndSellToken" ) )
244+ ) ;
245+ }
246+
247+ async fn test_execute_same_sell_and_buy_token ( web3 : Web3 ) {
248+ let mut onchain = OnchainComponents :: deploy ( web3. clone ( ) ) . await ;
249+
250+ let [ solver] = onchain. make_solvers ( eth ( 10 ) ) . await ;
251+ let [ trader] = onchain. make_accounts ( eth ( 10 ) ) . await ;
252+ let [ token] = onchain
253+ . deploy_tokens_with_weth_uni_v2_pools ( to_wei ( 1_000 ) , to_wei ( 1_000 ) )
254+ . await ;
255+
256+ token. mint ( trader. address ( ) , eth ( 10 ) ) . await ;
257+
258+ token
259+ . approve ( onchain. contracts ( ) . allowance . into_alloy ( ) , eth ( 10 ) )
260+ . from ( trader. address ( ) )
261+ . send_and_watch ( )
262+ . await
263+ . unwrap ( ) ;
264+
265+ tracing:: info!( "Starting services." ) ;
266+ let services = Services :: new ( & onchain) . await ;
267+ services
268+ . start_protocol_with_args (
269+ ExtraServiceArgs {
270+ api : vec ! [ "--allow-same-sell-and-buy-token=true" . to_string( ) ] ,
271+ ..Default :: default ( )
272+ } ,
273+ solver. clone ( ) ,
274+ )
275+ . await ;
276+
277+ // Disable auto-mine so we don't accidentally mine a settlement
278+ web3. api :: < TestNodeApi < _ > > ( )
279+ . set_automine_enabled ( false )
280+ . await
281+ . expect ( "Must be able to disable automine" ) ;
282+
283+ tracing:: info!( "Placing order" ) ;
284+ let initial_balance = token. balanceOf ( trader. address ( ) ) . call ( ) . await . unwrap ( ) ;
285+ assert_eq ! ( initial_balance, eth( 10 ) ) ;
286+
287+ let order_sell_amount = to_wei ( 2 ) ;
288+ let order_buy_amount = to_wei ( 1 ) ;
289+ let order = OrderCreation {
290+ sell_token : token. address ( ) . into_legacy ( ) ,
291+ sell_amount : order_sell_amount,
292+ buy_token : token. address ( ) . into_legacy ( ) ,
293+ buy_amount : order_buy_amount,
294+ valid_to : model:: time:: now_in_epoch_seconds ( ) + 300 ,
295+ kind : OrderKind :: Sell ,
296+ ..Default :: default ( )
297+ }
298+ . sign (
299+ EcdsaSigningScheme :: Eip712 ,
300+ & onchain. contracts ( ) . domain_separator ,
301+ SecretKeyRef :: from ( & SecretKey :: from_slice ( trader. private_key ( ) ) . unwrap ( ) ) ,
302+ ) ;
303+ assert ! ( services. create_order( & order) . await . is_ok( ) ) ;
304+
305+ // Start tracking confirmed blocks so we can find the transaction later
306+ let block_stream = web3
307+ . eth_filter ( )
308+ . create_blocks_filter ( )
309+ . await
310+ . expect ( "must be able to create blocks filter" )
311+ . stream ( Duration :: from_millis ( 50 ) ) ;
312+
313+ tracing:: info!( "Waiting for trade." ) ;
314+ onchain. mint_block ( ) . await ;
315+
316+ // Wait for settlement tx to appear in txpool
317+ wait_for_condition ( Duration :: from_secs ( 2 ) , || async {
318+ get_pending_tx ( solver. account ( ) . address ( ) , & web3)
319+ . await
320+ . is_some ( )
321+ } )
322+ . await
323+ . unwrap ( ) ;
324+
325+ // Continue mining to confirm the settlement
326+ web3. api :: < TestNodeApi < _ > > ( )
327+ . set_automine_enabled ( true )
328+ . await
329+ . expect ( "Must be able to enable automine" ) ;
330+
331+ // Wait for the settlement to be confirmed on chain
332+ let tx = tokio:: time:: timeout (
333+ Duration :: from_secs ( 5 ) ,
334+ get_confirmed_transaction ( solver. account ( ) . address ( ) , & web3, block_stream) ,
335+ )
336+ . await
337+ . unwrap ( ) ;
338+
339+ // Verify the transaction is to the settlement contract (not a cancellation)
340+ assert_eq ! (
341+ tx. to,
342+ Some ( onchain. contracts( ) . gp_settlement. address( ) . into_legacy( ) )
343+ ) ;
344+
345+ // Verify that the balance changed (settlement happened on chain)
346+ let trade_happened = || async {
347+ let balance = token. balanceOf ( trader. address ( ) ) . call ( ) . await . unwrap ( ) ;
348+ // Balance should change due to fees even if sell token == buy token
349+ balance != initial_balance
350+ } ;
351+ wait_for_condition ( TIMEOUT , trade_happened) . await . unwrap ( ) ;
352+
353+ let final_balance = token. balanceOf ( trader. address ( ) ) . call ( ) . await . unwrap ( ) ;
354+ tracing:: info!( ?initial_balance, ?final_balance, "Trade completed" ) ;
355+
356+ // Verify that the balance changed (settlement happened on chain)
357+ assert_ne ! ( final_balance, initial_balance) ;
358+ }
359+
126360async fn get_pending_tx ( account : H160 , web3 : & Web3 ) -> Option < web3:: types:: Transaction > {
127361 let txpool = web3
128362 . txpool ( )
0 commit comments