├── .gitignore ├── LICENSE ├── README.md ├── chains ├── mainnet.json └── testnet.json ├── index.js ├── package.json ├── src ├── chainUtils.js ├── checkBalance.js ├── displayHeader.js └── sleep.js └── target.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | package-lock.json 4 | privateKeys.json 5 | addresses.json 6 | rpc.txt -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2024 Dante4rt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EVM Auto Transfer 2 | 3 | Welcome to the `evm-auto-transfer` repository! This script allows you to automate transactions across multiple EVM-compatible networks. Whether you're interacting with testnets or mainnets, this tool simplifies the process, especially for tasks requiring multiple transfers. 4 | 5 | ## Features 6 | 7 | - 📡 Dynamic RPC URL, chain ID, and explorer integration from JSON files. 8 | - 🔄 Automated transaction processing for multiple addresses. 9 | - 🎯 Targeted transfers to specified addresses from `addresses.json`. 10 | - 🚀 Easily configurable for various networks (testnets and mainnets). 11 | - 🔒 Secure handling of private keys. 12 | 13 | ## Getting Started 14 | 15 | ### Prerequisites 16 | 17 | Ensure you have the following installed: 18 | 19 | - [Node.js](https://nodejs.org/) (v14 or higher) 20 | - npm (Node Package Manager) 21 | 22 | ### Installation 23 | 24 | 1. Clone the repository: 25 | 26 | ```bash 27 | git clone https://github.com/dante4rt/evm-auto-transfer.git 28 | cd evm-auto-transfer 29 | ``` 30 | 31 | 2. Install the necessary packages: 32 | 33 | ```bash 34 | npm install 35 | ``` 36 | 37 | ### Configuration 38 | 39 | 1. **Define the Chains**: 40 | 41 | - You'll need to specify the network details in JSON files located in the `/chains` directory. Create two JSON files: `testnet.json` and `mainnet.json`. 42 | - Each file should contain an array of objects with the following structure: 43 | 44 | ```json 45 | [ 46 | { 47 | "name": "Network Name", 48 | "rpcUrl": "https://rpc-url", 49 | "chainId": "1234", 50 | "symbol": "TOKEN", 51 | "explorer": "https://explorer-url" 52 | } 53 | ] 54 | ``` 55 | 56 | - Example for `testnet.json`: 57 | 58 | ```json 59 | [ 60 | { 61 | "name": "Plume Testnet", 62 | "rpcUrl": "https://plume-testnet-rpc.example.com", 63 | "chainId": "8888", 64 | "symbol": "PLUME", 65 | "explorer": "https://plume-testnet-explorer.example.com" 66 | } 67 | ] 68 | ``` 69 | 70 | 2. **Define Private Keys**: 71 | 72 | - Store your private keys securely inside a `privateKeys.json` file in the root directory. This file should contain an array of private keys as strings: 73 | 74 | ```json 75 | [ 76 | "0xYOUR_PRIVATE_KEY_1", 77 | "0xYOUR_PRIVATE_KEY_2" 78 | ] 79 | ``` 80 | 81 | **⚠️ Important**: Keep this file secure and avoid exposing your private keys! 82 | 83 | 3. **Create Target Addresses File**: 84 | 85 | - Create an `addresses.json` file in the root directory. This file should contain an array of target addresses you want to transfer funds to: 86 | 87 | ```json 88 | [ 89 | "0xTARGET_ADDRESS_1", 90 | "0xTARGET_ADDRESS_2" 91 | ] 92 | ``` 93 | 94 | ### Usage 95 | 96 | 1. Run the script for random address generation and transactions: 97 | 98 | ```bash 99 | npm start 100 | ``` 101 | 102 | 2. To use the targeted address feature, run: 103 | 104 | ```bash 105 | npm run target 106 | ``` 107 | 108 | - You will be prompted to select your network environment (Testnet/Mainnet) and choose the chain from the provided list using the arrow keys. 109 | - Define the number of transactions you want to process and let the script handle the rest! 110 | 111 | ### Contribution 112 | 113 | Contributions are welcome! Please fork the repository and submit a pull request with your improvements. 114 | 115 | ## Donations 116 | 117 | If you would like to support the development of this project, you can make a donation using the following addresses: 118 | 119 | - **Solana**: `GLQMG8j23ookY8Af1uLUg4CQzuQYhXcx56rkpZkyiJvP` 120 | - **EVM**: `0x960EDa0D16f4D70df60629117ad6e5F1E13B8F44` 121 | - **BTC**: `bc1p9za9ctgwwvc7amdng8gvrjpwhnhnwaxzj3nfv07szqwrsrudfh6qvvxrj8` 122 | 123 | ### License 124 | 125 | This project is licensed under the MIT License. See the `LICENSE` file for details. 126 | -------------------------------------------------------------------------------- /chains/mainnet.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Ethereum Mainnet", 4 | "rpcUrl": "https://mainnet.infura.io/v3", 5 | "chainId": "1", 6 | "symbol": "ETH", 7 | "explorer": "https://etherscan.io" 8 | }, 9 | { 10 | "name": "NCN Mainnet", 11 | "rpcUrl": "https://nc-rpc-prd1.neurochain.io", 12 | "chainId": "313", 13 | "symbol": "NCN", 14 | "explorer": "https://ncnscan.com" 15 | } 16 | ] 17 | -------------------------------------------------------------------------------- /chains/testnet.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Pharos Testnet", 4 | "rpcUrl": "https://testnet.dplabs-internal.com", 5 | "chainId": "688688", 6 | "symbol": "PHRS", 7 | "explorer": "https://testnet.pharosscan.xyz" 8 | }, 9 | { 10 | "name": "Tea Sepolia", 11 | "rpcUrl": "https://tea-sepolia.g.alchemy.com/public", 12 | "chainId": "10218", 13 | "symbol": "TEA", 14 | "explorer": "https://sepolia.tea.xyz" 15 | }, 16 | { 17 | "name": "Somnia Testnet", 18 | "rpcUrl": "https://dream-rpc.somnia.network", 19 | "chainId": "50312", 20 | "symbol": "STT", 21 | "explorer": "https://somnia-testnet.socialscan.io" 22 | }, 23 | { 24 | "name": "O3Layer Testnet", 25 | "rpcUrl": "https://testnet.rpc.o3layer.com", 26 | "chainId": "53574309564", 27 | "symbol": "O3", 28 | "explorer": "https://testnet.explorer.o3layer.com" 29 | }, 30 | { 31 | "name": "NERO Test Network", 32 | "rpcUrl": "https://rpc-testnet.nerochain.io", 33 | "chainId": "689", 34 | "symbol": "NERO", 35 | "explorer": "https://testnet.neroscan.io" 36 | }, 37 | { 38 | "name": "Monad Testnet", 39 | "rpcUrl": "https://testnet-rpc.monad.xyz", 40 | "chainId": "10143", 41 | "symbol": "MON", 42 | "explorer": "https://testnet.monadexplorer.com" 43 | }, 44 | { 45 | "name": "Rome Test Network", 46 | "rpcUrl": "https://rome.testnet.romeprotocol.xyz", 47 | "chainId": "200018", 48 | "symbol": "ROME", 49 | "explorer": "https://rome.testnet.romeprotocol.xyz:1000" 50 | }, 51 | { 52 | "name": "Reddio Development Network", 53 | "rpcUrl": "https://reddio-dev.reddio.com", 54 | "chainId": "50341", 55 | "symbol": "RED", 56 | "explorer": "https://reddio-devnet.l2scan.co" 57 | }, 58 | { 59 | "name": "Tea Assam Testnet", 60 | "rpcUrl": "https://assam-rpc.tea.xyz", 61 | "chainId": "93384", 62 | "symbol": "TEA", 63 | "explorer": "https://explorer-tea-assam-fo46m5b966.t.conduit.xyz:443" 64 | }, 65 | { 66 | "name": "Cypher Testnet", 67 | "rpcUrl": "https://testnet-rpc.cypher.z1labs.ai", 68 | "chainId": "10111", 69 | "symbol": "DEAI", 70 | "explorer": "https://testnet.cypherscan.ai" 71 | }, 72 | { 73 | "name": "Unichain Sepolia Testnet", 74 | "rpcUrl": "https://autumn-cosmological-scion.unichain-sepolia.quiknode.pro/c568806873f2a9edb9fcdea8aef0569ff729eb25", 75 | "chainId": "1301", 76 | "symbol": "ETH", 77 | "explorer": "https://testnet.brid.gg/sepolia" 78 | }, 79 | { 80 | "name": "Humanity Protocol Testnet", 81 | "rpcUrl": "https://rpc.testnet.humanity.org", 82 | "chainId": "1942999413", 83 | "symbol": "tHP", 84 | "explorer": "https://explorer.testnet.humanity.org" 85 | }, 86 | { 87 | "name": "Lumia Testnet", 88 | "rpcUrl": "https://lumia-testnet-rpc.eu-north-2.gateway.fm", 89 | "chainId": "1952959480", 90 | "symbol": "LUMIA", 91 | "explorer": "https://lumia-testnet-blockscout.eu-north-2.gateway.fm" 92 | }, 93 | { 94 | "name": "Testnet Onefinity", 95 | "rpcUrl": "https://testnet-rpc.onefinity.network", 96 | "chainId": "999987", 97 | "symbol": "ONE", 98 | "explorer": "https://testnet-explorer.onefinity.network" 99 | }, 100 | { 101 | "name": "PROM Testnet", 102 | "rpcUrl": "https://testnet-rpc.prom.io", 103 | "chainId": "584548796", 104 | "symbol": "T-PROM", 105 | "explorer": "https://testnet.promscan.io" 106 | }, 107 | { 108 | "name": "Tabi Testnetv2", 109 | "rpcUrl": "https://rpc.testnetv2.tabichain.com", 110 | "chainId": "9788", 111 | "symbol": "TABI", 112 | "explorer": "https://testnetv2.tabiscan.com" 113 | }, 114 | { 115 | "name": "Citrea Testnet", 116 | "rpcUrl": "https://rpc.testnet.citrea.xyz", 117 | "chainId": "5115", 118 | "symbol": "cBTC", 119 | "explorer": "https://explorer.testnet.citrea.xyz" 120 | }, 121 | { 122 | "name": "Open Campus", 123 | "rpcUrl": "https://rpc.open-campus-codex.gelato.digital", 124 | "chainId": "656476", 125 | "symbol": "EDU", 126 | "explorer": "https://opencampus-codex.blockscout.com" 127 | }, 128 | { 129 | "name": "Movement MEVM", 130 | "rpcUrl": "https://mevm.devnet.imola.movementlabs.xyz", 131 | "chainId": "30732", 132 | "symbol": "MOVE", 133 | "explorer": "https://explorer.devnet.imola.movementlabs.xyz" 134 | }, 135 | { 136 | "name": "Minato", 137 | "rpcUrl": "https://rpc.minato.soneium.org", 138 | "chainId": "1946", 139 | "symbol": "ETH", 140 | "explorer": "https://explorer-testnet.soneium.org" 141 | }, 142 | { 143 | "name": "Sonic Fantom Testnet", 144 | "rpcUrl": "https://rpc.testnet.soniclabs.com", 145 | "chainId": "64165", 146 | "symbol": "S", 147 | "explorer": "https://testnet.soniclabs.com" 148 | }, 149 | { 150 | "name": "Berachain bArtio", 151 | "rpcUrl": "https://bartio.rpc.berachain.com", 152 | "chainId": "80084", 153 | "symbol": "BERA", 154 | "explorer": "https://bartio.beratrail.io" 155 | }, 156 | { 157 | "name": "Plume Testnet", 158 | "rpcUrl": "https://testnet-rpc.plumenetwork.xyz/http", 159 | "chainId": "161221135", 160 | "symbol": "ETH", 161 | "explorer": "https://testnet-explorer.plumenetwork.xyz" 162 | }, 163 | { 164 | "name": "Unit Zero Testnet", 165 | "rpcUrl": "https://rpc-testnet.unit0.dev", 166 | "chainId": "88817", 167 | "symbol": "UNIT0", 168 | "explorer": "https://explorer-testnet.unit0.dev" 169 | }, 170 | { 171 | "name": "StratoVM Sepolia Testnet", 172 | "rpcUrl": "https://rpc.stratovm.io", 173 | "chainId": "93747", 174 | "symbol": "SVM", 175 | "explorer": "https://explorer.stratovm.io" 176 | }, 177 | { 178 | "name": "Story Testnet", 179 | "rpcUrl": "https://testnet.storyrpc.io", 180 | "chainId": "1513", 181 | "symbol": "IP", 182 | "explorer": "https://testnet.storyscan.xyz" 183 | }, 184 | { 185 | "name": "WeaveVM Testnet", 186 | "rpcUrl": "https://testnet.wvm.dev", 187 | "chainId": "9496", 188 | "symbol": "tWVM", 189 | "explorer": "https://explorer.wvm.dev" 190 | } 191 | ] 192 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require("ethers"); 2 | const colors = require("colors"); 3 | const fs = require("fs"); 4 | const readlineSync = require("readline-sync"); 5 | 6 | const checkBalance = require("./src/checkBalance"); 7 | const displayHeader = require("./src/displayHeader"); 8 | const sleep = require("./src/sleep"); 9 | const { loadChains, selectChain, selectNetworkType } = require("./src/chainUtils"); 10 | 11 | const MAX_RETRIES = 5; 12 | const RETRY_DELAY = 5000; 13 | 14 | async function retry(fn, maxRetries = MAX_RETRIES, delay = RETRY_DELAY) { 15 | for (let i = 0; i < maxRetries; i++) { 16 | try { 17 | return await fn(); 18 | } catch (error) { 19 | if (i === maxRetries - 1) throw error; 20 | console.log(colors.yellow(`⚠️ Error occurred. Retrying... (${i + 1}/${maxRetries})`)); 21 | await sleep(delay); 22 | } 23 | } 24 | } 25 | 26 | const main = async () => { 27 | displayHeader(); 28 | 29 | const networkType = selectNetworkType(); 30 | const chains = loadChains(networkType); 31 | const selectedChain = selectChain(chains); 32 | 33 | console.log(colors.green(`✅ You have selected: ${selectedChain.name}`)); 34 | console.log(colors.green(`🛠 RPC URL: ${selectedChain.rpcUrl}`)); 35 | console.log(colors.green(`🔗 Chain ID: ${selectedChain.chainId}`)); 36 | 37 | const provider = new ethers.JsonRpcProvider(selectedChain.rpcUrl); 38 | 39 | const privateKeys = JSON.parse(fs.readFileSync("privateKeys.json")); 40 | 41 | const transactionCount = readlineSync.questionInt( 42 | "Enter the number of transactions you want to send for each address: " 43 | ); 44 | 45 | for (const privateKey of privateKeys) { 46 | const wallet = new ethers.Wallet(privateKey, provider); 47 | const senderAddress = wallet.address; 48 | 49 | console.log(colors.cyan(`💼 Processing transactions for address: ${senderAddress}`)); 50 | 51 | let senderBalance; 52 | try { 53 | senderBalance = await retry(() => checkBalance(provider, senderAddress)); 54 | } catch (error) { 55 | console.log( 56 | colors.red(`❌ Failed to check balance for ${senderAddress}. Skipping to next address.`) 57 | ); 58 | continue; 59 | } 60 | 61 | if (senderBalance < ethers.parseUnits("0.0001", "ether")) { 62 | console.log(colors.red("❌ Insufficient or zero balance. Skipping to next address.")); 63 | continue; 64 | } 65 | 66 | let continuePrintingBalance = true; 67 | const printSenderBalance = async () => { 68 | while (continuePrintingBalance) { 69 | try { 70 | senderBalance = await retry(() => checkBalance(provider, senderAddress)); 71 | console.log( 72 | colors.blue( 73 | `💰 Current Balance: ${ethers.formatUnits(senderBalance, "ether")} ${ 74 | selectedChain.symbol 75 | }` 76 | ) 77 | ); 78 | if (senderBalance < ethers.parseUnits("0.0001", "ether")) { 79 | console.log(colors.red("❌ Insufficient balance for transactions.")); 80 | continuePrintingBalance = false; 81 | } 82 | } catch (error) { 83 | console.log(colors.red(`❌ Failed to check balance: ${error.message}`)); 84 | } 85 | await sleep(5000); 86 | } 87 | }; 88 | 89 | printSenderBalance(); 90 | 91 | for (let i = 1; i <= transactionCount; i++) { 92 | const receiverWallet = ethers.Wallet.createRandom(); 93 | const receiverAddress = receiverWallet.address; 94 | console.log(colors.white(`\n🆕 Generated address ${i}: ${receiverAddress}`)); 95 | 96 | const amountToSend = ethers.parseUnits( 97 | (Math.random() * (0.0000001 - 0.00000001) + 0.00000001).toFixed(10).toString(), 98 | "ether" 99 | ); 100 | 101 | /* --------------------------- TEMPORARY DISABLED --------------------------- */ 102 | // const gasPrice = ethers.parseUnits( 103 | // (Math.random() * (0.0015 - 0.0009) + 0.0009).toFixed(9).toString(), 104 | // 'gwei' 105 | // ); 106 | 107 | let gasPrice; 108 | try { 109 | gasPrice = (await provider.getFeeData()).gasPrice; 110 | } catch (error) { 111 | console.log(colors.red("❌ Failed to fetch gas price from the network.")); 112 | continue; 113 | } 114 | 115 | const transaction = { 116 | to: receiverAddress, 117 | value: amountToSend, 118 | gasLimit: 21000, 119 | gasPrice: gasPrice, 120 | chainId: parseInt(selectedChain.chainId), 121 | }; 122 | 123 | let tx; 124 | try { 125 | tx = await retry(() => wallet.sendTransaction(transaction)); 126 | } catch (error) { 127 | console.log(colors.red(`❌ Failed to send transaction: ${error.message}`)); 128 | continue; 129 | } 130 | 131 | console.log(colors.white(`🔗 Transaction ${i}:`)); 132 | console.log(colors.white(` Hash: ${colors.green(tx.hash)}`)); 133 | console.log(colors.white(` From: ${colors.green(senderAddress)}`)); 134 | console.log(colors.white(` To: ${colors.green(receiverAddress)}`)); 135 | console.log( 136 | colors.white( 137 | ` Amount: ${colors.green(ethers.formatUnits(amountToSend, "ether"))} ${ 138 | selectedChain.symbol 139 | }` 140 | ) 141 | ); 142 | console.log( 143 | colors.white(` Gas Price: ${colors.green(ethers.formatUnits(gasPrice, "gwei"))} Gwei`) 144 | ); 145 | 146 | await sleep(15000); 147 | 148 | let receipt; 149 | try { 150 | receipt = await retry(() => provider.getTransactionReceipt(tx.hash)); 151 | if (receipt) { 152 | if (receipt.status === 1) { 153 | console.log(colors.green("✅ Transaction Success!")); 154 | console.log(colors.green(` Block Number: ${receipt.blockNumber}`)); 155 | console.log(colors.green(` Gas Used: ${receipt.gasUsed.toString()}`)); 156 | console.log( 157 | colors.green(` Transaction hash: ${selectedChain.explorer}/tx/${receipt.hash}`) 158 | ); 159 | } else { 160 | console.log(colors.red("❌ Transaction FAILED")); 161 | } 162 | } else { 163 | console.log(colors.yellow("⏳ Transaction is still pending after multiple retries.")); 164 | } 165 | } catch (error) { 166 | console.log(colors.red(`❌ Error checking transaction status: ${error.message}`)); 167 | } 168 | 169 | console.log(); 170 | } 171 | 172 | console.log(colors.green(`✅ Finished transactions for address: ${senderAddress}`)); 173 | } 174 | 175 | console.log(""); 176 | console.log(colors.green("All transactions completed.")); 177 | console.log(colors.green("Subscribe: https://t.me/HappyCuanAirdrop.")); 178 | process.exit(0); 179 | }; 180 | 181 | main().catch((error) => { 182 | console.error(colors.red("🚨 An unexpected error occurred:"), error); 183 | process.exit(1); 184 | }); 185 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "evm-auto-transfer", 3 | "version": "1.0.0", 4 | "description": "Automate EVM transactions on testnets with ease. Configure your network and handle multiple transfers effortlessly using this bot.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node index.js", 9 | "target": "node target.js" 10 | }, 11 | "keywords": [ 12 | "automation", 13 | "EVM", 14 | "testnet", 15 | "transactions" 16 | ], 17 | "author": "dante4rt", 18 | "license": "MIT", 19 | "dependencies": { 20 | "axios": "^1.7.2", 21 | "colors": "^1.4.0", 22 | "ethers": "^6.13.1", 23 | "readline-sync": "^1.4.10" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/chainUtils.js: -------------------------------------------------------------------------------- 1 | const colors = require("colors"); 2 | const fs = require("fs"); 3 | const readlineSync = require("readline-sync"); 4 | 5 | function loadChains(networkType) { 6 | const filePath = `./chains/${networkType}.json`; 7 | 8 | if (!fs.existsSync(filePath)) { 9 | console.log(colors.red(`🚨 Error: The file ${filePath} does not exist.`)); 10 | process.exit(1); 11 | } 12 | 13 | const chains = JSON.parse(fs.readFileSync(filePath, "utf8")); 14 | 15 | if (chains.length === 0) { 16 | console.log(colors.red(`🚨 Error: No chains found in ${filePath}.`)); 17 | process.exit(1); 18 | } 19 | 20 | return chains; 21 | } 22 | 23 | function selectNetworkType() { 24 | const networkTypes = ["Testnet 🌐", "Mainnet 🔗"]; 25 | 26 | const selectedIndex = readlineSync.keyInSelect(networkTypes, "Select the network type:"); 27 | 28 | if (selectedIndex === -1) { 29 | console.log(colors.red("🚨 No network type selected. Exiting...")); 30 | process.exit(1); 31 | } 32 | 33 | return selectedIndex === 0 ? "testnet" : "mainnet"; 34 | } 35 | 36 | function selectChain(chains) { 37 | console.log(""); 38 | console.log(colors.cyan("🌐 Select a blockchain network:")); 39 | 40 | const chainNames = chains.map((chain) => { 41 | return `${chain.name}`; 42 | }); 43 | 44 | const selectedIndex = readlineSync.keyInSelect(chainNames, "Which chain do you want to use?"); 45 | 46 | if (selectedIndex === -1) { 47 | console.log(colors.red("🚨 No chain selected. Exiting...")); 48 | process.exit(1); 49 | } 50 | 51 | return chains[selectedIndex]; 52 | } 53 | 54 | module.exports = { loadChains, selectChain, selectNetworkType }; 55 | -------------------------------------------------------------------------------- /src/checkBalance.js: -------------------------------------------------------------------------------- 1 | const checkBalance = async (provider, address) => { 2 | const balance = await provider.getBalance(address); 3 | return balance; 4 | }; 5 | 6 | module.exports = checkBalance; 7 | -------------------------------------------------------------------------------- /src/displayHeader.js: -------------------------------------------------------------------------------- 1 | const colors = require("colors"); 2 | 3 | function displayHeader() { 4 | process.stdout.write("\x1Bc"); 5 | console.log(colors.cyan("========================================")); 6 | console.log(colors.cyan("= EVM Auto Transfer Bot =")); 7 | console.log(colors.cyan("= Created by HappyCuanAirdrop =")); 8 | console.log(colors.cyan("= https://t.me/HappyCuanAirdrop =")); 9 | console.log(colors.cyan("========================================")); 10 | console.log(); 11 | } 12 | 13 | module.exports = displayHeader; 14 | -------------------------------------------------------------------------------- /src/sleep.js: -------------------------------------------------------------------------------- 1 | const sleep = (ms) => { 2 | return new Promise((resolve) => setTimeout(resolve, ms)); 3 | }; 4 | 5 | module.exports = sleep; 6 | -------------------------------------------------------------------------------- /target.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require("ethers"); 2 | const colors = require("colors"); 3 | const fs = require("fs"); 4 | const readlineSync = require("readline-sync"); 5 | 6 | const checkBalance = require("./src/checkBalance"); 7 | const displayHeader = require("./src/displayHeader"); 8 | const sleep = require("./src/sleep"); 9 | const { loadChains, selectChain, selectNetworkType } = require("./src/chainUtils"); 10 | 11 | const MAX_RETRIES = 5; 12 | const RETRY_DELAY = 5000; 13 | 14 | async function retry(fn, maxRetries = MAX_RETRIES, delay = RETRY_DELAY) { 15 | for (let i = 0; i < maxRetries; i++) { 16 | try { 17 | return await fn(); 18 | } catch (error) { 19 | if (i === maxRetries - 1) throw error; 20 | console.log(colors.yellow(`⚠️ Error occurred. Retrying... (${i + 1}/${maxRetries})`)); 21 | await sleep(delay); 22 | } 23 | } 24 | } 25 | 26 | const main = async () => { 27 | displayHeader(); 28 | 29 | const networkType = selectNetworkType(); 30 | const chains = loadChains(networkType); 31 | const selectedChain = selectChain(chains); 32 | 33 | console.log(colors.green(`✅ You have selected: ${selectedChain.name}`)); 34 | console.log(colors.green(`🛠 RPC URL: ${selectedChain.rpcUrl}`)); 35 | console.log(colors.green(`🔗 Chain ID: ${selectedChain.chainId}`)); 36 | 37 | const provider = new ethers.JsonRpcProvider(selectedChain.rpcUrl); 38 | 39 | const privateKeys = JSON.parse(fs.readFileSync("privateKeys.json")); 40 | const recipientAddresses = JSON.parse(fs.readFileSync("addresses.json")); 41 | 42 | const transactionCount = readlineSync.questionInt( 43 | "Enter the number of transactions you want to send for each address: " 44 | ); 45 | 46 | for (const privateKey of privateKeys) { 47 | const wallet = new ethers.Wallet(privateKey, provider); 48 | const senderAddress = wallet.address; 49 | 50 | console.log(colors.cyan(`💼 Processing transactions for address: ${senderAddress}`)); 51 | 52 | let senderBalance; 53 | try { 54 | senderBalance = await retry(() => checkBalance(provider, senderAddress)); 55 | } catch (error) { 56 | console.log( 57 | colors.red(`❌ Failed to check balance for ${senderAddress}. Skipping to next address.`) 58 | ); 59 | continue; 60 | } 61 | 62 | if (senderBalance < ethers.parseUnits("0.001", "ether")) { 63 | console.log(colors.red("❌ Insufficient or zero balance. Skipping to next address.")); 64 | continue; 65 | } 66 | 67 | let continuePrintingBalance = true; 68 | const printSenderBalance = async () => { 69 | while (continuePrintingBalance) { 70 | try { 71 | senderBalance = await retry(() => checkBalance(provider, senderAddress)); 72 | console.log( 73 | colors.blue( 74 | `💰 Current Balance: ${ethers.formatUnits(senderBalance, "ether")} ${ 75 | selectedChain.symbol 76 | }` 77 | ) 78 | ); 79 | if (senderBalance < ethers.parseUnits("0.01", "ether")) { 80 | console.log(colors.red("❌ Insufficient balance for transactions.")); 81 | continuePrintingBalance = false; 82 | } 83 | } catch (error) { 84 | console.log(colors.red(`❌ Failed to check balance: ${error.message}`)); 85 | } 86 | await sleep(5000); 87 | } 88 | }; 89 | 90 | printSenderBalance(); 91 | 92 | for (let i = 1; i <= transactionCount; i++) { 93 | for (const receiverAddress of recipientAddresses) { 94 | console.log(colors.white(`\n🆕 Sending transaction ${i} to: ${receiverAddress}`)); 95 | 96 | const amountToSend = ethers.parseUnits( 97 | (Math.random() * (0.0000001 - 0.00000001) + 0.00000001).toFixed(10).toString(), 98 | "ether" 99 | ); 100 | 101 | let gasPrice; 102 | try { 103 | gasPrice = (await provider.getFeeData()).gasPrice; 104 | } catch (error) { 105 | console.log(colors.red("❌ Failed to fetch gas price from the network.")); 106 | continue; 107 | } 108 | 109 | const transaction = { 110 | to: receiverAddress, 111 | value: amountToSend, 112 | gasLimit: 21000, 113 | gasPrice: gasPrice, 114 | chainId: parseInt(selectedChain.chainId), 115 | }; 116 | 117 | let tx; 118 | try { 119 | tx = await retry(() => wallet.sendTransaction(transaction)); 120 | } catch (error) { 121 | console.log(colors.red(`❌ Failed to send transaction: ${error.message}`)); 122 | continue; 123 | } 124 | 125 | console.log(colors.white(`🔗 Transaction ${i}:`)); 126 | console.log(colors.white(` Hash: ${colors.green(tx.hash)}`)); 127 | console.log(colors.white(` From: ${colors.green(senderAddress)}`)); 128 | console.log(colors.white(` To: ${colors.green(receiverAddress)}`)); 129 | console.log( 130 | colors.white( 131 | ` Amount: ${colors.green(ethers.formatUnits(amountToSend, "ether"))} ${ 132 | selectedChain.symbol 133 | }` 134 | ) 135 | ); 136 | console.log( 137 | colors.white(` Gas Price: ${colors.green(ethers.formatUnits(gasPrice, "gwei"))} Gwei`) 138 | ); 139 | 140 | await sleep(15000); 141 | 142 | let receipt; 143 | try { 144 | receipt = await retry(() => provider.getTransactionReceipt(tx.hash)); 145 | if (receipt) { 146 | if (receipt.status === 1) { 147 | console.log(colors.green("✅ Transaction Success!")); 148 | console.log(colors.green(` Block Number: ${receipt.blockNumber}`)); 149 | console.log(colors.green(` Gas Used: ${receipt.gasUsed.toString()}`)); 150 | console.log( 151 | colors.green(` Transaction hash: ${selectedChain.explorer}/tx/${receipt.hash}`) 152 | ); 153 | } else { 154 | console.log(colors.red("❌ Transaction FAILED")); 155 | } 156 | } else { 157 | console.log(colors.yellow("⏳ Transaction is still pending after multiple retries.")); 158 | } 159 | } catch (error) { 160 | console.log(colors.red(`❌ Error checking transaction status: ${error.message}`)); 161 | } 162 | 163 | console.log(); 164 | } 165 | } 166 | 167 | console.log(colors.green(`✅ Finished transactions for address: ${senderAddress}`)); 168 | } 169 | 170 | console.log(colors.green("All transactions completed.")); 171 | console.log(colors.green("Subscribe: https://t.me/HappyCuanAirdrop.")); 172 | process.exit(0); 173 | }; 174 | 175 | main().catch((error) => { 176 | console.error(colors.red("🚨 An unexpected error occurred:"), error); 177 | process.exit(1); 178 | }); 179 | --------------------------------------------------------------------------------