Skip to content

Instantly share code, notes, and snippets.

@LionelB5
Last active December 5, 2024 04:20
Show Gist options
  • Save LionelB5/882415f735153800e3ae61c502925643 to your computer and use it in GitHub Desktop.
Save LionelB5/882415f735153800e3ae61c502925643 to your computer and use it in GitHub Desktop.
find-solana-balance
// Find a Solana address matching an arbitrary criteria that is based on:
// - Address's last activity
// - Balance of the address
//
// Script is rough and quickly put together, use at your own risk. Intended to be run in a Deno notebook.
import { Connection, PublicKey } from "npm:@solana/web3.js@latest";
const RPC_ENDPOINT = "https://api.mainnet-beta.solana.com";
const MIN_BALANCE = 20 * 1e9; // 20 SOL in lamports
const INACTIVE_PERIOD = 6 * 30 * 24 * 60 * 60; // 6 months in seconds
const connection = new Connection(RPC_ENDPOINT, {
fetch: async (url, options) => {
let retries = 0;
const maxRetries = Infinity; // Set the maximum number of retries you want
const retryDelay = 5000; // Delay between retries (in ms)
// Loop to retry indefinitely (or maxRetries times)
while (retries < maxRetries) {
try {
// Try making the fetch request
const response = await fetch(url, options);
if (response.ok) {
return response;
} else {
throw new Error(`Fetch failed with status: ${response.status}`);
}
} catch (error) {
retries++;
console.log(`Fetch attempt ${retries} failed: ${error.message}`);
if (retries >= maxRetries) {
throw new Error('Maximum retries reached');
}
// Wait before retrying
await new Promise(resolve => setTimeout(resolve, retryDelay));
}
}
},
});
async function findInactiveAddress(startingSlot) {
const minTimestamp = Math.floor(Date.now() / 1000) - INACTIVE_PERIOD;
let currentSlot = startingSlot;
while (currentSlot > 0) {
console.log(`Scanning block: ${currentSlot}`);
// Fetch transactions in the current slot
const blockData = await connection.getBlock(currentSlot, {
maxSupportedTransactionVersion: 0,
});
if (!blockData || !blockData.transactions) {
console.log(`No transactions in block ${currentSlot}`);
currentSlot -= 1;
continue;
}
for (const transaction of blockData.transactions) {
if (!Array.isArray(transaction.transaction.message.accountKeys)) {
continue;
}
// Check all accounts involved in the transaction
for (const accountKey of transaction.transaction.message.accountKeys) {
const publicKey = new PublicKey(accountKey.toString());
// Fetch balance
const balance = await connection.getBalance(publicKey);
// Skip if balance is less than MIN_BALANCE
if (balance < MIN_BALANCE) continue;
// Fetch recent transaction history
const recentTransactions = await connection.getSignaturesForAddress(
publicKey,
{ limit: 1 }
);
const isInactive = recentTransactions.length === 0 ||
recentTransactions[0].blockTime < minTimestamp;
if (isInactive) {
console.log(`Found address: ${publicKey.toString()}`);
console.log(`Balance: ${balance / 1e9} SOL`);
return publicKey.toString(); // Exit once a match is found
}
}
}
currentSlot -= 1; // Move to the previous block
}
console.log("No address found meeting the criteria.");
return null;
}
// Replace this with the starting block number
const startingBlock = 204452876; // Example block number
await findInactiveAddress(startingBlock)
.then((result) => {
if (result) {
console.log(`Address found: ${result}`);
} else {
console.log("No suitable address found.");
}
})
.catch((error) => {
console.error("Error occurred:", error);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment