A Triangular Arbitrage Opportunity

2024年6月23日 20:00:00

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

inf

Step 1

First, you can swap $SOL to $INF using @JupiterExchange via Meteora DLMM or Orca, that is a DEX aggregator on Solana.

Step 2

Then, you can swap $INF to $jitoSOL using @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, 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}`);
}
Tags: