├── result.json ├── requirements.txt ├── .gitignore ├── config.json └── parser.py /result.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | python-dotenv==1.0.0 2 | solana==0.32.0 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | env 2 | .env 3 | runs 4 | /solana-insiders-finder -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "HASBULL": { 3 | "mint": "9ywnj3fxk7ry5yvvzw5peefjyiuh683u9r92efbwcnqf", 4 | "before_hash": "478pyqpJzVBB6CFSut1FZR5cv3hHx9dYq2nxEukwkTpPHG8Nay5oNqV3eDNQx48Yx5xN7dU7FzbywbhSiPDy9UNt", 5 | "after_hash": "4MtpKKGhTx2MrHnyKz7RJSqK2DB7w1HW2eRwDLAqyZDmZWjERMuEhssZajbsybppAnLkdYPJHqgtGBZ8hsaRDDXK" 6 | }, 7 | "moar": { 8 | "mint": "AWcq8cy2gYhfgmiV1RowHiaP8ohAU1d4A2AL5Zm9pump", 9 | "before_hash": "4r2Y1UnNdrV76KZdGzhhpmpBDR2VvJWg4Tmfbbn1kZZQKSpWeppxWwHn9M7287C1jvyy6ksMH2K3KvaFzFnWFVks", 10 | "after_hash": "4GXFV2qFNfCMALyT4skCxBuVEbxLkx65as4gXqLoPqSwskg6NLtHzJueprU5hkfYNxZMwTTg3zSVr2QKL8CiVcqp" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /parser.py: -------------------------------------------------------------------------------- 1 | import time 2 | from solders.pubkey import Pubkey 3 | from solders.signature import Signature 4 | from solana.rpc.api import Client 5 | import json 6 | import math 7 | import os 8 | from dotenv import load_dotenv 9 | 10 | load_dotenv() 11 | 12 | 13 | client = Client(os.getenv("HTTP_NODE_URL")) 14 | min_percentage = 80 15 | 16 | 17 | def get_mint_transactions(token_name, mint, limit=100, before=None, after=None): 18 | TOTAL_LIMIT = 300000 19 | signatures = [] 20 | try: 21 | while True: 22 | mint_address = Pubkey.from_string(mint) 23 | new_signatures = client.get_signatures_for_address( 24 | mint_address, limit=limit, before=before).value 25 | if not new_signatures: 26 | break 27 | 28 | for signature in new_signatures: 29 | if after and signature.signature == after: 30 | print(f"Reached after_hash for token {token_name}, stopping.") 31 | return signatures, before 32 | 33 | signatures.append(signature) 34 | 35 | print("New signatures len:", len( 36 | new_signatures), "for:", token_name) 37 | before = new_signatures[-1].signature 38 | if len(signatures) >= TOTAL_LIMIT: 39 | break 40 | except Exception as e: 41 | print(f"Error for token {token_name}: {e}") 42 | return signatures, before 43 | 44 | 45 | def check_transaction_for_swap(signature): 46 | try: 47 | if type(signature) == str: 48 | signature = Signature.from_string(signature) 49 | tx_info = client.get_transaction( 50 | signature, 51 | max_supported_transaction_version=1, 52 | encoding='base64' 53 | ).value 54 | signer_address = tx_info.transaction.transaction.message.account_keys[0] 55 | return signer_address 56 | except Exception as e: 57 | print(f"Error checking transaction {signature}: {e}") 58 | return None 59 | 60 | 61 | def parse_transactions(token_name, transactions): 62 | wallets = [] 63 | try: 64 | for tx in transactions: 65 | address = check_transaction_for_swap(tx.signature) 66 | if address: 67 | wallet_string = str(address) 68 | wallets.append(wallet_string) 69 | time.sleep(0.2) 70 | return wallets 71 | except Exception as e: 72 | print(f"Error parsing for token {token_name}: {e}") 73 | 74 | 75 | def find_common_wallets(wallets_by_token, min_percentage): 76 | total_tokens = len(wallets_by_token) 77 | min_token_count = math.ceil((min_percentage / 100) * total_tokens) 78 | 79 | wallet_count = {} 80 | 81 | for token_name, wallets in wallets_by_token.items(): 82 | for wallet in set(wallets): 83 | if wallet not in wallet_count: 84 | wallet_count[wallet] = {'count': 0, 'tokens': []} 85 | wallet_count[wallet]['count'] += 1 86 | wallet_count[wallet]['tokens'].append(token_name) 87 | 88 | common_wallets = { 89 | wallet: data['tokens'] 90 | for wallet, data in wallet_count.items() if data['count'] >= min_token_count 91 | } 92 | 93 | return common_wallets 94 | 95 | 96 | if __name__ == "__main__": 97 | # result = check_transaction_for_swap("32ffe61RVuH9ziqBkxuec8uGFDfD52fhFzpg44ZtUoq9CpkLPCLdEgdQAi4ubgNf8cdhLgAB97abC5PkHMVDGB14") 98 | # print(result) 99 | 100 | with open('config.json', 'r') as f: 101 | mint_data = json.load(f) 102 | wallets_by_token = {} 103 | 104 | for token_name, token_data in mint_data.items(): 105 | mint = token_data['mint'] 106 | before_hash = Signature.from_string( 107 | token_data['before_hash']) if token_data['before_hash'] else None 108 | after_hash = Signature.from_string( 109 | token_data['after_hash']) if token_data['after_hash'] else None 110 | 111 | transactions, new_before_hash = get_mint_transactions( 112 | token_name, mint, limit=1000, before=before_hash, after=after_hash) 113 | 114 | mint_data[token_name]['before_hash'] = new_before_hash 115 | 116 | wallets = parse_transactions(token_name, transactions) 117 | wallets_by_token[token_name] = wallets 118 | 119 | common_wallets = find_common_wallets(wallets_by_token, min_percentage) 120 | 121 | if common_wallets: 122 | with open('result.json', 'w') as f: 123 | json.dump(common_wallets, f, indent=4) 124 | print( 125 | f"Wallets count (appearing in at least {min_percentage}% of tokens): {len(common_wallets)}") 126 | else: 127 | print( 128 | f"No wallets found that appear in at least {min_percentage}% of tokens.") 129 | --------------------------------------------------------------------------------