@@ -15,6 +15,8 @@ use crate::{
1515 constant:: { TokenAddress , u128_to_uint256} ,
1616 types:: connector:: AutoSwappr ,
1717} ;
18+ use reqwest:: Client ;
19+ use serde_json:: json;
1820#[ allow( dead_code) ]
1921type EkuboResponse = Result <
2022 starknet:: core:: types:: InvokeTransactionResult ,
@@ -110,46 +112,76 @@ impl AutoSwappr {
110112 }
111113
112114 // pub async fn ekubo_auto_swap(){
113- // // todo steph
114- // // approve contract to spend
115- // // sent a post request to auto swapper backend
116- // // post request arg will look like this
117- // // ====== wallet_address, user address
118- // // ======= to_token,
119- // // ======= from_token,
120- // // ======= swap_amount,
121-
122- // // below is how the approval fall will look
123- // // handle error
124-
125- // // let account = approver_signer_account();
126-
127- // // if !is_valid_address(token) {
128- // // return Err("INVALID TOKEN ADDRESS".to_string());
129- // // }
130-
131- // // let spender = contract_address_felt();
132-
133- // // let token = Felt::from_hex(token).expect("TOKEN ADDRESS NOT PROVIDED");
134-
135- // // // Convert amount to uint256 (split into low and high parts)
136- // // let (amount_low, amount_high) = u128_to_uint256(amount);
137-
138- // // // Prepare the calldata: [spender, amount_low, amount_high]
139- // // let calldata = vec![spender, amount_low, amount_high];
140-
141- // // let call = Call {
142- // // to: token,
143- // // selector: get_selector_from_name("approve").unwrap(),
144- // // calldata,
145- // // };
146- // // let execution = account
147- // // .execute_v3(vec![call])
148- // // .send()
149- // // .await
150- // // .map_err(|e| e.to_string())?;
151- // // Ok(execution.transaction_hash)
152- // }
115+ // Implemented: approve token and notify backend for auto-swap
116+ pub async fn ekubo_auto_swap (
117+ & mut self ,
118+ token_from : Felt ,
119+ token_to : Felt ,
120+ amount : u128 ,
121+ backend_url : & str ,
122+ ) -> Result < String , String > {
123+ if amount == 0 {
124+ return Err ( "ZERO SWAP AMOUNT" . to_string ( ) ) ;
125+ }
126+
127+ // ensure token is supported to derive decimals
128+ let token_decimal = TokenAddress :: new ( )
129+ . get_token_info_by_address ( token_from)
130+ . map_err ( |e| e. to_string ( ) ) ?
131+ . decimals ;
132+
133+ let actual_amount = amount * 10_u128 . pow ( token_decimal as u32 ) ;
134+ let ( amount_low, amount_high) = u128_to_uint256 ( actual_amount) ;
135+
136+ // Prepare approve call to allow contract to spend `token_from`
137+ let approve_call = Call {
138+ to : token_from,
139+ selector : selector ! ( "approve" ) ,
140+ calldata : vec ! [ self . contract_address, amount_low, amount_high] ,
141+ } ;
142+
143+ // set preconfirmed block for querying
144+ self . account
145+ . set_block_id ( BlockId :: Tag ( BlockTag :: PreConfirmed ) ) ;
146+
147+ // send approve transaction
148+ let approve_result = self
149+ . account
150+ . execute_v3 ( vec ! [ approve_call] )
151+ . send ( )
152+ . await
153+ . map_err ( |e| format ! ( "approve failed: {}" , e) ) ?;
154+
155+ // Prepare payload for backend
156+ let payload = json ! ( {
157+ "wallet_address" : format!( "0x{:x}" , self . account. address( ) ) ,
158+ "user_address" : format!( "0x{:x}" , self . account. address( ) ) ,
159+ "to_token" : format!( "0x{:x}" , token_to) ,
160+ "from_token" : format!( "0x{:x}" , token_from) ,
161+ "swap_amount" : actual_amount. to_string( ) ,
162+ "approve_tx_hash" : format!( "0x{:x}" , approve_result. transaction_hash) ,
163+ } ) ;
164+
165+ let client = Client :: new ( ) ;
166+ let resp = client
167+ . post ( backend_url)
168+ . json ( & payload)
169+ . send ( )
170+ . await
171+ . map_err ( |e| format ! ( "network error: {}" , e) ) ?;
172+
173+ let status = resp. status ( ) ;
174+ let text = resp
175+ . text ( )
176+ . await
177+ . map_err ( |e| format ! ( "response read error: {}" , e) ) ?;
178+
179+ if status. is_success ( ) {
180+ Ok ( text)
181+ } else {
182+ Err ( format ! ( "backend error: {} - {}" , status, text) )
183+ }
184+ }
153185}
154186
155187#[ cfg( test) ]
@@ -184,4 +216,24 @@ mod tests {
184216 // assert!(result.await.clone().is_ok());
185217 println ! ( "test complete {:?}" , result. await . ok( ) ) ;
186218 }
219+
220+ #[ tokio:: test]
221+ #[ ignore = "owner address, private key and backend required to run the test" ]
222+ async fn it_works_auto ( ) {
223+ // This test exercises `ekubo_auto_swap` flow: approve + notify backend.
224+ // It is ignored by default because it requires a funded wallet and a reachable backend.
225+ let rpc_url = "YOUR MAINNET RPC" . to_string ( ) ;
226+ let account_address = "YOUR WALLET ADDRESS" . to_string ( ) ;
227+ let private_key = "YOUR WALLET PRIVATE KEY" . to_string ( ) ;
228+ let mut swapper = AutoSwappr :: config ( rpc_url, account_address, private_key) ;
229+
230+ // Use STRK -> USDC for a tiny amount (1 unit). Backend URL is a placeholder and
231+ // should be replaced with a real auto-swapper endpoint when running the test.
232+ let backend_url = "https://example.com/api/auto-swap" ;
233+ let result = swapper. ekubo_auto_swap ( * STRK , * USDC , 1 , backend_url) ;
234+
235+ // Print the result (Ok response body or Err description). The test is ignored
236+ // so it won't run in CI unless explicitly enabled.
237+ println ! ( "auto swap test result: {:?}" , result. await ) ;
238+ }
187239}
0 commit comments