# A Triangular Arbitrage Opportunity

By [xiaorun.eth](https://paragraph.com/@xiaorun.eth) · 2024-07-16

arbitrage

---

ThisThis article introduces a triangular arbitrage opportunity from a few months ago.

![inf](https://storage.googleapis.com/papyrus_images/5c91ae7550aa584af82dd6bffa19f9a4.png)

Step 1
------

First, you can swap $SOL to $INF using [@JupiterExchange](https://x.com/JupiterExchange) via Meteora DLMM or Orca, that is a DEX aggregator on Solana.

Step 2
------

Then, you can swap $INF to $jitoSOL using [@sanctumso](https://x.com/sanctumso) via its infinite LST liquidity pool.

Step 3
------

Finnally, you can delayed unstake $jitoSOL to retain $SOL in the next epoch using [@jito\_sol](https://x.com/jito_sol), that is a solana liquid staking pool. Remember, manually deactivate your stake account by clicking on the "Deactivate" button on jito's Manage Stake Accounts page or in your wallet. Once your stake has finished deactivating click on the "Withdraw" button to withdraw SOL.

Some code
---------

    async function step1_On_Jup(solAmount) {
        // Swapping SOL to INF
        const quoteResponse = await (
            await fetch('https://quote-api.jup.ag/v6/quote?' + new URLSearchParams({
                inputMint: solMint,
                outputMint: infMint,
                amount: solAmount,
                slippageBps: slippageBps,
              })
            )
        ).json();
    
        console.log(`Swapping ${solAmount/oneAmount} SOL to ${quoteResponse.outAmount/oneAmount} INF`);
    
        // https://station.jup.ag/docs/apis/swap-api
        const { swapTransaction } = await (
                await fetch('https://quote-api.jup.ag/v6/swap', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    quoteResponse,
                    userPublicKey: wallet.publicKey.toString(),
                    dynamicComputeUnitLimit: true,
                    prioritizationFeeLamports: 'auto'
                })
            })
        ).json();
    
        const swapTransactionBuf = Buffer.from(swapTransaction, 'base64');
        var transaction = VersionedTransaction.deserialize(swapTransactionBuf);
    
        transaction.sign([wallet.payer]);
    
        const rawTransaction = transaction.serialize()
        const txid = await connection.sendRawTransaction(rawTransaction, {
            skipPreflight: true,
            maxRetries: 2
        });
        await connection.confirmTransaction(txid);
        console.log(`https://solscan.io/tx/${txid}`);
    
        step2_On_Sanctum( quoteResponse.outAmount );
    }
    
    async function step2_On_Sanctum(infAmount) {
        // Swapping INF to jitoSOL
        const quoteResponse = await (
            await fetch('https://sanctum-s-api.fly.dev/v1/swap/quote?' + new URLSearchParams({
                input: infMint,
                outputLstMint: jitosolMint,
                amount: infAmount,
                mode: 'ExactIn'
              })
            )
        ).json();
    
        console.log(`Swapping ${infAmount/oneAmount} INF to ${quoteResponse.outAmount/oneAmount} jitoSOL`);
    
        // https://sanctum-s-api.fly.dev/#/LST%20Swaps/handle_swap
        const swapTransaction = await (
            await fetch('https://sanctum-s-api.fly.dev/v1/swap', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    input: infMint,
                    outputLstMint: jitosolMint,
                    amount: quoteResponse.inAmount,
                    quotedAmount: quoteResponse.outAmount,
                    swapSrc: quoteResponse.swapSrc,
                    mode: 'ExactIn',
                    signer: wallet.publicKey.toString(),
                })
            })
        ).json();
    
        const swapTransactionBuf = Buffer.from(swapTransaction.tx, 'base64');
        var transaction = VersionedTransaction.deserialize(swapTransactionBuf);
    
        transaction.sign([wallet.payer]);
    
        const rawTransaction = transaction.serialize()
        const txid = await connection.sendRawTransaction(rawTransaction, {
            skipPreflight: true,
            maxRetries: 2
        });
        await connection.confirmTransaction(txid);
        console.log(`https://solscan.io/tx/${txid}`);
    }

---

*Originally published on [xiaorun.eth](https://paragraph.com/@xiaorun.eth/a-triangular-arbitrage-opportunity)*
