0

I am trying to build a node js app that take my Tatum.io solana wallet address which have SOL and USD-Coins and make swap. I want to convert USDC from my wallet to SOL or convert SOL to USD-Coins. the current code execute successfully and fee deducted from my SOL balance but no transfer happend USD Coins are the same as before after executing transfer.

I am also looking for a detailed guide on swapping SPL tokens in both ways.

I really appreciate if someone can help :(

Node js



const express = require('express');
const { Connection, Keypair, PublicKey, Transaction, SystemProgram, LAMPORTS_PER_SOL, clusterApiUrl, sendAndConfirmTransaction } = require('@solana/web3.js');
const { getAssociatedTokenAddress, createAssociatedTokenAccountInstruction, createTransferInstruction, TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID } = require('@solana/spl-token');
const bs58 = require('bs58');
require('dotenv').config();

const app = express();
app.use(express.json());

const connection = new Connection(clusterApiUrl("devnet"), 'confirmed');
const secretKey = bs58.decode(process.env.WALLET_PRIVATE_KEY);
const payer = Keypair.fromSecretKey(secretKey);

const USDC_MINT = new PublicKey(process.env.USDC_MINT_ADDRESS);

async function getSolEquivalent(usdcAmount) {
    // In a production environment, you should fetch real-time price data
    const conversionRate = 0.0005;
    return usdcAmount * conversionRate;
}

app.post('/swap', async (req, res) => {
    const { userPublicKey, usdcAmount } = req.body;

    if (!userPublicKey || !usdcAmount) {
        return res.status(400).json({ error: 'Missing userPublicKey or usdcAmount' });
    }

    try {
        const userPublicKeyObj = new PublicKey(userPublicKey);

        // Get token accounts
        const userUsdcAddress = await getAssociatedTokenAddress(
            USDC_MINT,
            userPublicKeyObj
        );

        const payerUsdcAddress = await getAssociatedTokenAddress(
            USDC_MINT,
            payer.publicKey
        );

        // Verify USDC balance
        const userUsdcBalance = await connection.getTokenAccountBalance(userUsdcAddress)
            .catch(() => ({ value: { amount: '0' } }));

        const usdcAmountInDecimals = usdcAmount * (10 ** 6);
        if (Number(userUsdcBalance.value.amount) < usdcAmountInDecimals) {
            return res.status(400).json({ error: 'Insufficient USDC balance' });
        }

        // Create transaction
        const transaction = new Transaction();

        // Check if user's USDC account exists
        const userUsdcAccountInfo = await connection.getAccountInfo(userUsdcAddress);
        if (!userUsdcAccountInfo) {
            transaction.add(
                createAssociatedTokenAccountInstruction(
                    payer.publicKey,
                    userUsdcAddress,
                    userPublicKeyObj,
                    USDC_MINT
                )
            );
        }

        // Check if payer's USDC account exists
        const payerUsdcAccountInfo = await connection.getAccountInfo(payerUsdcAddress);
        if (!payerUsdcAccountInfo) {
            transaction.add(
                createAssociatedTokenAccountInstruction(
                    payer.publicKey,
                    payerUsdcAddress,
                    payer.publicKey,
                    USDC_MINT
                )
            );
        }

        // Add USDC transfer instruction
        const transferInstruction = createTransferInstruction(
            userUsdcAddress,
            payerUsdcAddress,
            userPublicKeyObj,
            usdcAmountInDecimals
        );
        transaction.add(transferInstruction);

        // Calculate and verify SOL amount
        const solAmount = await getSolEquivalent(usdcAmount);
        const payerBalance = await connection.getBalance(payer.publicKey);
        const requiredSol = solAmount * LAMPORTS_PER_SOL;

        if (payerBalance < requiredSol) {
            return res.status(400).json({ error: 'Insufficient SOL balance for swap' });
        }

        // Add SOL transfer instruction
        const solTransferInstruction = SystemProgram.transfer({
            fromPubkey: payer.publicKey,
            toPubkey: userPublicKeyObj,
            lamports: requiredSol,
        });
        transaction.add(solTransferInstruction);

        // Set recent blockhash and fee payer
        const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
        transaction.recentBlockhash = blockhash;
        transaction.feePayer = payer.publicKey;

        // Sign and send transaction
        transaction.sign(payer);

        const signature = await sendAndConfirmTransaction(
            connection,
            transaction,
            [payer],
            {
                skipPreflight: false,
                preflightCommitment: 'confirmed',
                commitment: 'confirmed'
            }
        );

        // Verify transaction success
        const confirmedTransaction = await connection.getTransaction(signature, {
            commitment: 'confirmed',
        });

        if (!confirmedTransaction?.meta?.err) {
            res.status(200).json({
                signature,
                message: 'Swap transaction successful!',
                solAmount,
                usdcAmount
            });
        } else {
            throw new Error('Transaction failed');
        }

    } catch (error) {
        console.error('Error processing swap:', error);
        res.status(500).json({
            error: 'Transaction failed',
            details: error.message
        });
    }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});
1
  • This might be a silly question, but are payer.publicKey and userPublicKeyObj the same? If so, it would make sense that nothing happens during the transfer!
    – Jon C
    Commented Nov 20 at 17:31

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.