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}`);
});
payer.publicKey
anduserPublicKeyObj
the same? If so, it would make sense that nothing happens during the transfer!