Can someone please help me understand why I'm getting this error? I'm trying to perform this automatic transaction through websocket the moment the account receives any funds. I'm pretty sure the feeInLamports is correct, because when I try manually and check the transaction in Solscan, 21000 lamports (0.000021 SOL) is showing as FEE. I event tried to increase the fee amount, but still showing the same error.
import WebSocket = require("ws");
import { Keypair, PublicKey, SystemProgram } from '@solana/web3.js';
const web3 = require('@solana/web3.js');
const ws = new WebSocket("wss://api.mainnet-beta.solana.com");
const WALLET_1_PRIVATE_KEY = Uint8Array.from([...]);
const receiverAccount = new PublicKey("...");
const privateKeyBuffer = Buffer.from(WALLET_1_PRIVATE_KEY);
const senderAccountKeyPair = Keypair.fromSecretKey(privateKeyBuffer);
const connection = new web3.Connection(web3.clusterApiUrl('mainnet-beta'));
async function commitTransaction() {
await connection.getBalance(senderAccountKeyPair.publicKey).then((balance: any) => {
let feeInLamports = 21000;
let amountToSend = balance - feeInLamports;
if (balance >= amountToSend && amountToSend > feeInLamports) {
let transaction = new web3.Transaction().add(
web3.SystemProgram.transfer({
fromPubkey: senderAccountKeyPair.publicKey,
toPubkey: receiverAccount,
lamports: amountToSend,
programId: SystemProgram.programId,
})
);
console.log("[transaction] balance =", balance);
console.log("[transaction] amountToSend =", amountToSend);
async function sendTransactionWithRetry(transaction: any, signers: any, maxRetries = 5, delayMs = 1000) {
let retries = 0;
while (retries < maxRetries) {
try {
await web3.sendAndConfirmTransaction(
connection,
transaction,
signers
);
console.log("Transaction sent successfully.");
} catch (error) {
console.error(`Error sending transaction: ${error}`);
if (retries < maxRetries - 1) {
console.log(`Retrying transaction in ${delayMs} ms...`);
new Promise(resolve => setTimeout(resolve, delayMs));
}
}
retries++;
}
console.error("Max retries reached. Transaction failed.");
}
sendTransactionWithRetry(transaction, [senderAccountKeyPair]);
} else {
console.log('Insufficient balance for the transaction.')
}
})
}
function subscribeToAccount(ws: WebSocket, account: string){
const requestData = {
"jsonrpc": "2.0",
"id": 135791,
"method": "accountSubscribe",
"params": [
account.toString(),
{
"encoding": "jsonParsed",
"commitment": "finalized"
}
]
};
ws.send(JSON.stringify(requestData))
console.log("Subcribed to account")
}
ws.addEventListener("open", () => {
console.log("new connection!")
subscribeToAccount(ws, senderAccountKeyPair.publicKey.toString());
setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
subscribeToAccount(ws, senderAccountKeyPair.publicKey.toString())
}
}, 45000);
});
ws.onmessage = async (event) => {
try {
const data = JSON.parse(Buffer.from(event.data).toString('utf-8'));
console.log('On message event data:', data);
if (data && data.params && data.params.result && data.params.result.value && data.params.result.value.lamports) {
// let balance = data.params.result.value.lamports;
await commitTransaction()
} else {
console.log('Invalid or missing data in the WebSocket message.');
}
} catch (error) {
console.error('Error parsing event data:', error);
};
};
let reconnectInterval = 1000; // Initial reconnect interval in milliseconds
let maxReconnectAttempts = 5;
ws.onclose = () => {
console.log('WebSocket connection closed.');
if (maxReconnectAttempts > 0) {
setTimeout(() => {
subscribeToAccount(ws, senderAccountKeyPair.publicKey.toString());
maxReconnectAttempts--;
reconnectInterval *= 2; // Exponential backoff
}, reconnectInterval);
} else {
console.log('Maximum reconnection attempts reached.');
}
};
ws.onerror = (error) => {
console.error('WebSocket error:', error);
};