11//! Jupiter swap-API adapter.
22//!
3- //! v1 `/quote` + `/swap-instructions` (ExactIn). Triton is a base-URL and key
4- //! swap behind the same adapter.
3+ //! v1 `/quote` + `/swap-instructions` (ExactIn for sells, ExactOut for buys).
4+ //! Triton is a base-URL and key swap behind the same adapter.
55
66mod dto;
77
@@ -20,6 +20,7 @@ pub struct Jupiter {
2020 endpoint : reqwest:: Url ,
2121 api_key : Option < String > ,
2222 slippage_bps : u16 ,
23+ enable_buy_orders : bool ,
2324}
2425
2526impl Jupiter {
@@ -29,17 +30,19 @@ impl Jupiter {
2930 endpoint : config. endpoint . clone ( ) ,
3031 api_key : config. api_key . clone ( ) ,
3132 slippage_bps : config. slippage_bps ,
33+ enable_buy_orders : config. enable_buy_orders ,
3234 } )
3335 }
3436
3537 /// Quote `order` for the settlement signer `taker` and return the swap to
3638 /// run inside the settlement transaction.
3739 pub async fn swap ( & self , order : & Order , taker : & Pubkey ) -> Result < Swap , Error > {
38- // Buy orders (ExactOut) aren't served here.
39- if order. side == Side :: Buy {
40- return Err ( Error :: OrderNotSupported ) ;
41- }
42- let quote = self . quote ( order, "ExactIn" ) . await ?;
40+ let swap_mode = match order. side {
41+ Side :: Sell => "ExactIn" ,
42+ Side :: Buy if self . enable_buy_orders => "ExactOut" ,
43+ Side :: Buy => return Err ( Error :: OrderNotSupported ) ,
44+ } ;
45+ let quote = self . quote ( order, swap_mode) . await ?;
4346 let in_amount = amount_field ( & quote, "inAmount" ) ?;
4447 let out_amount = amount_field ( & quote, "outAmount" ) ?;
4548 self . swap_instructions ( & quote, taker, & order. buy_destination )
@@ -151,32 +154,29 @@ mod tests {
151154 const USDC : & str = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" ;
152155 const WSOL : & str = "So11111111111111111111111111111111111111112" ;
153156
154- fn config ( ) -> JupiterConfig {
157+ fn config ( enable_buy_orders : bool ) -> JupiterConfig {
155158 JupiterConfig {
156159 endpoint : "https://api.jup.ag" . parse ( ) . unwrap ( ) ,
157160 api_key : std:: env:: var ( "JUPITER_API_KEY" ) . ok ( ) ,
158161 slippage_bps : 50 ,
162+ enable_buy_orders,
159163 }
160164 }
161165
162- fn sell_order ( ) -> Order {
166+ fn order ( side : Side ) -> Order {
163167 Order {
164168 sell_mint : Pubkey :: from_str ( USDC ) . unwrap ( ) ,
165169 buy_mint : Pubkey :: from_str ( WSOL ) . unwrap ( ) ,
166170 buy_destination : Pubkey :: from_str ( WSOL ) . unwrap ( ) ,
167171 amount : 1_000_000 ,
168- side : Side :: Sell ,
172+ side,
169173 }
170174 }
171175
172176 #[ tokio:: test]
173- async fn buy_unsupported ( ) {
174- let jupiter = Jupiter :: new ( & config ( ) ) . unwrap ( ) ;
175- let order = Order {
176- side : Side :: Buy ,
177- ..sell_order ( )
178- } ;
179- let result = jupiter. swap ( & order, & Pubkey :: new_unique ( ) ) . await ;
177+ async fn buy_disabled ( ) {
178+ let jupiter = Jupiter :: new ( & config ( false ) ) . unwrap ( ) ;
179+ let result = jupiter. swap ( & order ( Side :: Buy ) , & Pubkey :: new_unique ( ) ) . await ;
180180 assert ! ( matches!( result, Err ( Error :: OrderNotSupported ) ) ) ;
181181 }
182182
@@ -205,15 +205,31 @@ mod tests {
205205 #[ tokio:: test]
206206 #[ ignore]
207207 async fn jupiter_live_sell ( ) {
208- let jupiter = Jupiter :: new ( & config ( ) ) . unwrap ( ) ;
208+ let jupiter = Jupiter :: new ( & config ( false ) ) . unwrap ( ) ;
209209 // Any valid pubkey works for building instructions, the swap only runs
210210 // for real once the driver supplies its settlement signer.
211211 let swap = jupiter
212- . swap ( & sell_order ( ) , & Pubkey :: from_str ( WSOL ) . unwrap ( ) )
212+ . swap ( & order ( Side :: Sell ) , & Pubkey :: from_str ( WSOL ) . unwrap ( ) )
213213 . await
214214 . unwrap ( ) ;
215215 assert_eq ! ( swap. in_amount, 1_000_000 ) ;
216216 assert ! ( swap. out_amount > 0 ) ;
217217 assert ! ( !swap. instructions. is_empty( ) ) ;
218218 }
219+
220+ /// Live Jupiter API. Needs network. Keyless works, set `JUPITER_API_KEY`
221+ /// for headroom.
222+ #[ tokio:: test]
223+ #[ ignore]
224+ async fn jupiter_live_buy ( ) {
225+ let jupiter = Jupiter :: new ( & config ( true ) ) . unwrap ( ) ;
226+ // ExactOut: the swap delivers exactly the order's `amount` of buy mint.
227+ let swap = jupiter
228+ . swap ( & order ( Side :: Buy ) , & Pubkey :: from_str ( WSOL ) . unwrap ( ) )
229+ . await
230+ . unwrap ( ) ;
231+ assert_eq ! ( swap. out_amount, 1_000_000 ) ;
232+ assert ! ( swap. in_amount > 0 ) ;
233+ assert ! ( !swap. instructions. is_empty( ) ) ;
234+ }
219235}
0 commit comments