├── address.txt ├── pvkey.txt ├── scripts ├── __init__.py ├── bebop.py ├── izumi.py ├── mono.py ├── magma.py ├── deploy.py ├── sendtx.py ├── kintsu.py ├── lilchogstars.py ├── rubic.py ├── apriori.py ├── uniswap.py ├── bean.py ├── ambient.py └── bima.py ├── requirements.txt ├── main.py └── README.md /address.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pvkey.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /scripts/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | inquirer 2 | web3 3 | colorama 4 | py-solc-x 5 | eth-account 6 | loguru 7 | aiohttp 8 | requests -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import importlib 4 | import inquirer 5 | import asyncio 6 | from scripts.apriori import get_quote 7 | from colorama import init, Fore, Style 8 | 9 | # Initialize colorama 10 | init(autoreset=True) 11 | 12 | # Fixed border width 13 | BORDER_WIDTH = 80 14 | 15 | def print_border(text: str, color=Fore.CYAN, width=BORDER_WIDTH): 16 | text = text.strip() 17 | if len(text) > width - 4: 18 | text = text[:width - 7] + "..." 19 | padded_text = f" {text} ".center(width - 2) 20 | print(f"{color}┌{'─' * (width - 2)}┐{Style.RESET_ALL}") 21 | print(f"{color}│{padded_text}│{Style.RESET_ALL}") 22 | print(f"{color}└{'─' * (width - 2)}┘{Style.RESET_ALL}") 23 | 24 | def _banner(): 25 | print(f"{Fore.GREEN}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 26 | print_border("MONAD TESTNET", Fore.GREEN) 27 | print(f"{Fore.GREEN}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 28 | 29 | def _clear(): 30 | os.system('cls' if os.name == 'nt' else 'clear') 31 | 32 | def get_available_scripts(): 33 | return [ 34 | {"name": "1. Rubic Swap", "value": "rubic"}, 35 | {"name": "2. Magma Staking", "value": "magma"}, 36 | {"name": "3. Izumi Swap", "value": "izumi"}, 37 | {"name": "4. aPriori Staking", "value": "apriori"}, 38 | {"name": "5. Kintsu Staking", "value": "kintsu"}, 39 | {"name": "6. Bean Swap", "value": "bean"}, 40 | {"name": "7. Monorail Swap", "value": "mono"}, 41 | {"name": "8. Bebop Swap", "value": "bebop"}, 42 | {"name": "9. Ambient Finance Swap", "value": "ambient"}, 43 | {"name": "10. Uniswap Swap", "value": "uniswap"}, 44 | {"name": "11. Deploy Contract", "value": "deploy"}, 45 | {"name": "12. Send Random TX or File (address.txt)", "value": "sendtx"}, 46 | {"name": "13. Bima Deposit bmBTC", "value": "bima"}, 47 | {"name": "14. Mint NFT Lil Chogstars", "value": "lilchogstars"}, 48 | {"name": "17. Exit", "value": "exit"} 49 | ] 50 | 51 | def run_script(script_module): 52 | """Run script whether it's async or not.""" 53 | run_func = script_module.run 54 | if asyncio.iscoroutinefunction(run_func): 55 | asyncio.run(run_func()) 56 | else: 57 | run_func() 58 | 59 | def main(): 60 | _clear() 61 | _banner() 62 | 63 | while True: 64 | _clear() 65 | _banner() 66 | get_quote() 67 | print_border("MAIN MENU", Fore.YELLOW) 68 | 69 | available_scripts = get_available_scripts() 70 | questions = [ 71 | inquirer.List('script', 72 | message=f"{Fore.CYAN}Select script to run{Style.RESET_ALL}", 73 | choices=[script["name"] for script in available_scripts], 74 | carousel=True) 75 | ] 76 | answers = inquirer.prompt(questions) 77 | if not answers: 78 | continue 79 | 80 | selected_script_name = answers['script'] 81 | selected_script_value = next(script["value"] for script in available_scripts if script["name"] == selected_script_name) 82 | 83 | if selected_script_value == "exit": 84 | print(f"{Fore.GREEN}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 85 | print_border("EXITING", Fore.GREEN) 86 | print(f"{Fore.YELLOW}👋 {'Goodbye!':^76}{Style.RESET_ALL}") 87 | print(f"{Fore.GREEN}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 88 | sys.exit(0) 89 | 90 | try: 91 | print(f"{Fore.CYAN}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 92 | print_border(f"RUNNING: {selected_script_name}", Fore.CYAN) 93 | script_module = importlib.import_module(f"scripts.{selected_script_value}") 94 | run_script(script_module) 95 | print(f"{Fore.GREEN}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 96 | print_border(f"Completed {selected_script_name}", Fore.GREEN) 97 | input(f"{Fore.YELLOW}⏎ Press Enter to continue...{Style.RESET_ALL:^76}") 98 | except ImportError: 99 | print(f"{Fore.RED}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 100 | print_border(f"Script not found: {selected_script_value}", Fore.RED) 101 | input(f"{Fore.YELLOW}⏎ Press Enter to continue...{Style.RESET_ALL:^76}") 102 | except Exception as e: 103 | print(f"{Fore.RED}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 104 | print_border(f"Error: {str(e)}", Fore.RED) 105 | input(f"{Fore.YELLOW}⏎ Press Enter to continue...{Style.RESET_ALL:^76}") 106 | 107 | if __name__ == "__main__": 108 | main() 109 | -------------------------------------------------------------------------------- /scripts/bebop.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | import time 4 | from colorama import init, Fore, Style 5 | from web3 import Web3 6 | 7 | # Initialize colorama 8 | init(autoreset=True) 9 | 10 | # Constants 11 | RPC_URL = "https://testnet-rpc.monad.xyz/" 12 | EXPLORER_URL = "https://testnet.monadexplorer.com/tx/0x" 13 | WMON_CONTRACT = "0x760AfE86e5de5fa0Ee542fc7B7B713e1c5425701" 14 | 15 | # Display border function 16 | def print_border(text, color=Fore.CYAN, width=60): 17 | print(f"{color}┌{'─' * (width - 2)}┐{Style.RESET_ALL}") 18 | print(f"{color}│ {text:^19} │{Style.RESET_ALL}") 19 | print(f"{color}└{'─' * (width - 2)}┘{Style.RESET_ALL}") 20 | 21 | # Display step function 22 | def print_step(step, message): 23 | steps = { 24 | 'wrap': 'Wrap MON', 25 | 'unwrap': 'Unwrap WMON' 26 | } 27 | step_text = steps[step] 28 | print(f"{Fore.YELLOW}➤ {Fore.CYAN}{step_text:<15}{Style.RESET_ALL} | {message}") 29 | 30 | # Load private keys from prkeys.txt 31 | def load_private_keys(file_path): 32 | try: 33 | with open(file_path, 'r') as file: 34 | return [line.strip() for line in file.readlines() if line.strip()] 35 | except FileNotFoundError: 36 | return None 37 | except Exception as e: 38 | print(f"{Fore.RED}❌ Error reading file: {str(e)}{Style.RESET_ALL}") 39 | return None 40 | 41 | # Initialize web3 provider 42 | w3 = Web3(Web3.HTTPProvider(RPC_URL)) 43 | 44 | # Smart contract ABI 45 | contract_abi = [ 46 | {"constant": False, "inputs": [], "name": "deposit", "outputs": [], "payable": True, "stateMutability": "payable", "type": "function"}, 47 | {"constant": False, "inputs": [{"name": "amount", "type": "uint256"}], "name": "withdraw", "outputs": [], "payable": False, "stateMutability": "nonpayable", "type": "function"}, 48 | ] 49 | 50 | # Initialize contract 51 | contract = w3.eth.contract(address=WMON_CONTRACT, abi=contract_abi) 52 | 53 | # Get MON amount from user 54 | def get_mon_amount_from_user(): 55 | while True: 56 | try: 57 | print_border("Enter MON amount (0.01 - 999)", Fore.YELLOW) 58 | amount = float(input(f"{Fore.GREEN}➤ {Style.RESET_ALL}")) 59 | if 0.01 <= amount <= 999: 60 | return w3.to_wei(amount, 'ether') 61 | print(f"{Fore.RED}❌ Amount must be 0.01-999 / Enter a valid number!{Style.RESET_ALL}") 62 | except ValueError: 63 | print(f"{Fore.RED}❌ Amount must be 0.01-999 / Enter a valid number!{Style.RESET_ALL}") 64 | 65 | # Random delay (60-180 seconds) 66 | def get_random_delay(): 67 | return random.randint(60, 180) 68 | 69 | # Wrap MON to WMON 70 | def wrap_mon(private_key, amount): 71 | try: 72 | account = w3.eth.account.from_key(private_key) 73 | wallet = account.address[:8] + "..." 74 | 75 | print_border(f"Wrap {w3.from_wei(amount, 'ether')} MON → WMON | {wallet}") 76 | tx = contract.functions.deposit().build_transaction({ 77 | 'from': account.address, 78 | 'value': amount, 79 | 'gas': 500000, 80 | 'gasPrice': w3.to_wei('100', 'gwei'), 81 | 'nonce': w3.eth.get_transaction_count(account.address), 82 | }) 83 | 84 | print_step('wrap', 'Sending transaction...') 85 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 86 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 87 | 88 | print_step('wrap', f"Tx: {Fore.YELLOW}{EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 89 | w3.eth.wait_for_transaction_receipt(tx_hash) 90 | print_step('wrap', f"{Fore.GREEN}Wrap successful!{Style.RESET_ALL}") 91 | 92 | except Exception as e: 93 | print_step('wrap', f"{Fore.RED}Failed: {str(e)}{Style.RESET_ALL}") 94 | raise 95 | 96 | # Unwrap WMON to MON 97 | def unwrap_mon(private_key, amount): 98 | try: 99 | account = w3.eth.account.from_key(private_key) 100 | wallet = account.address[:8] + "..." 101 | 102 | print_border(f"Unwrap {w3.from_wei(amount, 'ether')} WMON → MON | {wallet}") 103 | tx = contract.functions.withdraw(amount).build_transaction({ 104 | 'from': account.address, 105 | 'gas': 500000, 106 | 'gasPrice': w3.to_wei('50', 'gwei'), 107 | 'nonce': w3.eth.get_transaction_count(account.address), 108 | }) 109 | 110 | print_step('unwrap', 'Sending transaction...') 111 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 112 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 113 | 114 | print_step('unwrap', f"Tx: {Fore.YELLOW}{EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 115 | w3.eth.wait_for_transaction_receipt(tx_hash) 116 | print_step('unwrap', f"{Fore.GREEN}Unwrap successful!{Style.RESET_ALL}") 117 | 118 | except Exception as e: 119 | print_step('unwrap', f"{Fore.RED}Failed: {str(e)}{Style.RESET_ALL}") 120 | raise 121 | 122 | # Run swap cycle 123 | def run_swap_cycle(cycles, private_keys): 124 | for cycle in range(1, cycles + 1): 125 | for pk in private_keys: 126 | wallet = w3.eth.account.from_key(pk).address[:8] + "..." 127 | msg = f"CYCLE {cycle}/{cycles} | Account: {wallet}" 128 | print(f"{Fore.CYAN}{'═' * 60}{Style.RESET_ALL}") 129 | print(f"{Fore.CYAN}│ {msg:^56} │{Style.RESET_ALL}") 130 | print(f"{Fore.CYAN}{'═' * 60}{Style.RESET_ALL}") 131 | 132 | amount = get_mon_amount_from_user() 133 | wrap_mon(pk, amount) 134 | unwrap_mon(pk, amount) 135 | 136 | if cycle < cycles or pk != private_keys[-1]: 137 | delay = get_random_delay() 138 | print(f"\n{Fore.YELLOW}⏳ Waiting {delay} seconds...{Style.RESET_ALL}") 139 | time.sleep(delay) 140 | 141 | def run(): 142 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 143 | print(f"{Fore.GREEN}│ {'BEBOP SWAP - MONAD TESTNET':^56} │{Style.RESET_ALL}") 144 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 145 | 146 | # Load private keys 147 | private_keys = load_private_keys('pvkey.txt') 148 | if not private_keys: 149 | print(f"{Fore.RED}❌ prkeys.txt not found{Style.RESET_ALL}") 150 | return 151 | 152 | print(f"{Fore.CYAN}👥 Accounts: {len(private_keys)}{Style.RESET_ALL}") 153 | 154 | # Get number of cycles 155 | while True: 156 | try: 157 | print_border("NUMBER OF CYCLES", Fore.YELLOW) 158 | cycles = input(f"{Fore.GREEN}➤ Enter number (default 1): {Style.RESET_ALL}") 159 | cycles = int(cycles) if cycles else 1 160 | if cycles > 0: 161 | break 162 | print(f"{Fore.RED}❌ Number must be > 0{Style.RESET_ALL}") 163 | except ValueError: 164 | print(f"{Fore.RED}❌ Enter a valid number{Style.RESET_ALL}") 165 | 166 | # Run script 167 | print(f"{Fore.YELLOW}🚀 Running {cycles} swap cycles...{Style.RESET_ALL}") 168 | run_swap_cycle(cycles, private_keys) 169 | 170 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 171 | print(f"{Fore.GREEN}│ {'ALL DONE':^19} │{Style.RESET_ALL}") 172 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 173 | 174 | if __name__ == "__main__": 175 | run() 176 | -------------------------------------------------------------------------------- /scripts/izumi.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | import asyncio 4 | from web3 import Web3 5 | from colorama import init, Fore, Style 6 | 7 | # Initialize colorama 8 | init(autoreset=True) 9 | 10 | # Constants 11 | RPC_URL = "https://testnet-rpc.monad.xyz/" 12 | EXPLORER_URL = "https://testnet.monadexplorer.com/tx/0x" 13 | WMON_CONTRACT = "0x760AfE86e5de5fa0Ee542fc7B7B713e1c5425701" 14 | 15 | # Load private keys from pvkey.txt 16 | def load_private_keys(file_path): 17 | try: 18 | with open(file_path, 'r') as file: 19 | keys = [line.strip() for line in file.readlines() if line.strip()] 20 | if not keys: 21 | raise ValueError("pvkey.txt is empty") 22 | return keys 23 | except FileNotFoundError: 24 | print(f"{Fore.RED}❌ pvkey.txt not found{Style.RESET_ALL}") 25 | return None 26 | except Exception as e: 27 | print(f"{Fore.RED}❌ Error reading pvkey.txt: {str(e)}{Style.RESET_ALL}") 28 | return None 29 | 30 | # Initialize web3 provider 31 | w3 = Web3(Web3.HTTPProvider(RPC_URL)) 32 | 33 | # Check connection 34 | if not w3.is_connected(): 35 | print(f"{Fore.RED}❌ Could not connect to RPC{Style.RESET_ALL}") 36 | exit(1) 37 | 38 | # Initialize contract 39 | contract = w3.eth.contract(address=WMON_CONTRACT, abi=[ 40 | {"constant": False, "inputs": [], "name": "deposit", "outputs": [], "payable": True, "stateMutability": "payable", "type": "function"}, 41 | {"constant": False, "inputs": [{"name": "amount", "type": "uint256"}], "name": "withdraw", "outputs": [], "payable": False, "stateMutability": "nonpayable", "type": "function"}, 42 | ]) 43 | 44 | # Print border function 45 | def print_border(text, color=Fore.CYAN, width=60): 46 | print(f"{color}┌{'─' * (width - 2)}┐{Style.RESET_ALL}") 47 | print(f"{color}│ {text:^56} │{Style.RESET_ALL}") 48 | print(f"{color}└{'─' * (width - 2)}┘{Style.RESET_ALL}") 49 | 50 | # Print step function 51 | def print_step(step, message): 52 | step_text = "Wrap MON" if step == 'wrap' else "Unwrap WMON" 53 | print(f"{Fore.YELLOW}➤ {Fore.CYAN}{step_text:<15}{Style.RESET_ALL} | {message}") 54 | 55 | # Generate random amount (0.01 - 0.05 MON) 56 | def get_random_amount(): 57 | min_val = 0.01 58 | max_val = 0.05 59 | random_amount = random.uniform(min_val, max_val) 60 | return w3.to_wei(round(random_amount, 4), 'ether') 61 | 62 | # Generate random delay (1-3 minutes) 63 | def get_random_delay(): 64 | return random.randint(60, 180) # Returns seconds 65 | 66 | # Wrap MON to WMON 67 | async def wrap_mon(private_key, amount): 68 | try: 69 | account = w3.eth.account.from_key(private_key) 70 | wallet = account.address[:8] + "..." 71 | 72 | print_border(f"Wrapping {w3.from_wei(amount, 'ether')} MON → WMON | {wallet}") 73 | tx = contract.functions.deposit().build_transaction({ 74 | 'from': account.address, 75 | 'value': amount, 76 | 'gas': 500000, 77 | 'gasPrice': w3.eth.gas_price, 78 | 'nonce': w3.eth.get_transaction_count(account.address), 79 | }) 80 | 81 | print_step('wrap', 'Sending transaction...') 82 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 83 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 84 | 85 | print_step('wrap', f"Tx: {Fore.YELLOW}{EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 86 | await asyncio.sleep(1) 87 | w3.eth.wait_for_transaction_receipt(tx_hash) 88 | print_step('wrap', f"{Fore.GREEN}Wrap successful!{Style.RESET_ALL}") 89 | 90 | except Exception as e: 91 | print_step('wrap', f"{Fore.RED}Failed: {str(e)}{Style.RESET_ALL}") 92 | raise 93 | 94 | # Unwrap WMON to MON 95 | async def unwrap_mon(private_key, amount): 96 | try: 97 | account = w3.eth.account.from_key(private_key) 98 | wallet = account.address[:8] + "..." 99 | 100 | print_border(f"Unwrapping {w3.from_wei(amount, 'ether')} WMON → MON | {wallet}") 101 | tx = contract.functions.withdraw(amount).build_transaction({ 102 | 'from': account.address, 103 | 'gas': 500000, 104 | 'gasPrice': w3.eth.gas_price, 105 | 'nonce': w3.eth.get_transaction_count(account.address), 106 | }) 107 | 108 | print_step('unwrap', 'Sending transaction...') 109 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 110 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 111 | 112 | print_step('unwrap', f"Tx: {Fore.YELLOW}{EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 113 | await asyncio.sleep(1) 114 | w3.eth.wait_for_transaction_receipt(tx_hash) 115 | print_step('unwrap', f"{Fore.GREEN}Unwrap successful!{Style.RESET_ALL}") 116 | 117 | except Exception as e: 118 | print_step('unwrap', f"{Fore.RED}Failed: {str(e)}{Style.RESET_ALL}") 119 | raise 120 | 121 | # Run swap cycle for each private key 122 | async def run_swap_cycle(cycles, private_keys): 123 | for account_idx, private_key in enumerate(private_keys, 1): 124 | wallet = w3.eth.account.from_key(private_key).address[:8] + "..." 125 | print_border(f"ACCOUNT {account_idx}/{len(private_keys)} | {wallet}", Fore.CYAN) 126 | 127 | for i in range(cycles): 128 | print_border(f"SWAP CYCLE {i + 1}/{cycles} | {wallet}") 129 | amount = get_random_amount() 130 | await wrap_mon(private_key, amount) 131 | await unwrap_mon(private_key, amount) 132 | if i < cycles - 1: 133 | delay = get_random_delay() 134 | print(f"\n{Fore.YELLOW}⏳ Waiting {delay / 60:.1f} minutes before next cycle...{Style.RESET_ALL}") 135 | await asyncio.sleep(delay) 136 | 137 | if account_idx < len(private_keys): 138 | delay = get_random_delay() 139 | print(f"\n{Fore.YELLOW}⏳ Waiting {delay / 60:.1f} minutes before next account...{Style.RESET_ALL}") 140 | await asyncio.sleep(delay) 141 | 142 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 143 | print(f"{Fore.GREEN}│ ALL DONE: {cycles} CYCLES FOR {len(private_keys)} ACCOUNTS{' ' * (32 - len(str(cycles)) - len(str(len(private_keys))))}│{Style.RESET_ALL}") 144 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 145 | 146 | # Main function 147 | async def run(): 148 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 149 | print(f"{Fore.GREEN}│ {'IZUMI SWAP - MONAD TESTNET':^56} │{Style.RESET_ALL}") 150 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 151 | 152 | private_keys = load_private_keys('pvkey.txt') 153 | if not private_keys: 154 | return 155 | 156 | print(f"{Fore.CYAN}👥 Accounts: {len(private_keys)}{Style.RESET_ALL}") 157 | 158 | while True: 159 | try: 160 | print_border("NUMBER OF CYCLES", Fore.YELLOW) 161 | cycles_input = input(f"{Fore.GREEN}➤ Enter number (default 1): {Style.RESET_ALL}") 162 | cycles = int(cycles_input) if cycles_input.strip() else 1 163 | if cycles <= 0: 164 | raise ValueError 165 | break 166 | except ValueError: 167 | print(f"{Fore.RED}❌ Please enter a valid number!{Style.RESET_ALL}") 168 | 169 | print(f"{Fore.YELLOW}🚀 Running {cycles} swap cycles immediately for {len(private_keys)} accounts...{Style.RESET_ALL}") 170 | await run_swap_cycle(cycles, private_keys) 171 | 172 | if __name__ == "__main__": 173 | asyncio.run(run()) 174 | -------------------------------------------------------------------------------- /scripts/mono.py: -------------------------------------------------------------------------------- 1 | import os 2 | import asyncio 3 | import random 4 | from web3 import Web3 5 | from colorama import init, Fore, Style 6 | 7 | # Initialize colorama 8 | init(autoreset=True) 9 | 10 | # Constants 11 | RPC_URL = "https://testnet-rpc.monad.xyz" 12 | EXPLORER_URL = "https://testnet.monadexplorer.com/tx/0x" 13 | CONTRACT_ADDRESS = "0xC995498c22a012353FAE7eCC701810D673E25794" 14 | 15 | def load_private_keys(file_path='pvkey.txt'): 16 | try: 17 | with open(file_path, 'r') as file: 18 | keys = [line.strip() for line in file.readlines() if line.strip()] 19 | if not keys: 20 | raise ValueError("pvkey.txt is empty") 21 | return keys 22 | except FileNotFoundError: 23 | print(f"{Fore.RED}❌ pvkey.txt not found{Style.RESET_ALL}") 24 | return None 25 | except Exception as e: 26 | print(f"{Fore.RED}❌ Error reading pvkey.txt: {str(e)}{Style.RESET_ALL}") 27 | return None 28 | 29 | # Initialize web3 provider 30 | w3 = Web3(Web3.HTTPProvider(RPC_URL)) 31 | 32 | # Check connection 33 | if not w3.is_connected(): 34 | print(f"{Fore.RED}❌ Could not connect to RPC{Style.RESET_ALL}") 35 | exit(1) 36 | 37 | def print_border(text, color=Fore.CYAN, width=60): 38 | print(f"{color}┌{'─' * (width - 2)}┐{Style.RESET_ALL}") 39 | print(f"{color}│ {text:^56} │{Style.RESET_ALL}") 40 | print(f"{color}└{'─' * (width - 2)}┘{Style.RESET_ALL}") 41 | 42 | async def check_balance(wallet_address): 43 | print(f"{Fore.YELLOW}🔍 Checking balance...{Style.RESET_ALL}") 44 | balance = await asyncio.get_event_loop().run_in_executor(None, lambda: w3.eth.get_balance(wallet_address)) 45 | balance_eth = w3.from_wei(balance, 'ether') 46 | print(f"{Fore.CYAN}💰 Balance: {balance_eth} MONAD{Style.RESET_ALL}") 47 | 48 | if balance < w3.to_wei(0.1, 'ether') + w3.to_wei(0.01, 'ether'): # 0.1 ETH + gas fee buffer 49 | print(f"{Fore.RED}❌ Insufficient balance for transaction!{Style.RESET_ALL}") 50 | return False 51 | return True 52 | 53 | 54 | async def send_transaction(private_key): 55 | try: 56 | account = w3.eth.account.from_key(private_key) 57 | wallet_address = account.address 58 | wallet_short = wallet_address[:8] + "..." 59 | 60 | print_border(f"Starting Monorail for {wallet_short}") 61 | if not await check_balance(wallet_address): 62 | return 63 | 64 | data = "0x96f25cbe0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0590015a873bf326bd645c3e1266d4db41c4e6b000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000" + wallet_address.replace('0x', '').lower() + "000000000000000000000000000000000000000000000000542f8f7c3d64ce470000000000000000000000000000000000000000000000000000002885eeed340000000000000000000000000000000000000000000000000000000000000004000000000000000000000000760afe86e5de5fa0ee542fc7b7b713e1c5425701000000000000000000000000760afe86e5de5fa0ee542fc7b7b713e1c5425701000000000000000000000000cba6b9a951749b8735c603e7ffc5151849248772000000000000000000000000760afe86e5de5fa0ee542fc7b7b713e1c54257010000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000004d0e30db0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044095ea7b3000000000000000000000000cba6b9a951749b8735c603e7ffc5151849248772000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010438ed1739000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000000000000000000000000000542f8f7c3d64ce4700000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000c995498c22a012353fae7ecc701810d673e257940000000000000000000000000000000000000000000000000000002885eeed340000000000000000000000000000000000000000000000000000000000000002000000000000000000000000760afe86e5de5fa0ee542fc7b7b713e1c5425701000000000000000000000000e0590015a873bf326bd645c3e1266d4db41c4e6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044095ea7b3000000000000000000000000cba6b9a951749b8735c603e7ffc5151849248772000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 65 | value = w3.to_wei(0.1, 'ether') 66 | 67 | try: 68 | gas_limit = await asyncio.get_event_loop().run_in_executor(None, lambda: w3.eth.estimate_gas({ 69 | 'from': wallet_address, 70 | 'to': CONTRACT_ADDRESS, 71 | 'value': value, 72 | 'data': data 73 | })) 74 | except Exception as e: 75 | print(f"{Fore.YELLOW}⚠️ Gas estimation failed. Using default gas limit. ({str(e)}){Style.RESET_ALL}") 76 | gas_limit = 500000 77 | 78 | tx = { 79 | 'from': wallet_address, 80 | 'to': CONTRACT_ADDRESS, 81 | 'data': data, 82 | 'value': value, 83 | 'gas': gas_limit, 84 | 'gasPrice': w3.eth.gas_price, 85 | 'nonce': w3.eth.get_transaction_count(wallet_address), 86 | } 87 | 88 | print(f"{Fore.BLUE}🚀 Sending transaction...{Style.RESET_ALL}") 89 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 90 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 91 | 92 | print(f"{Fore.GREEN}✅ Transaction sent! Waiting for confirmation...{Style.RESET_ALL}") 93 | await asyncio.sleep(1) 94 | receipt = w3.eth.wait_for_transaction_receipt(tx_hash) 95 | 96 | print(f"{Fore.GREEN}🎉 Transaction successful!{Style.RESET_ALL}") 97 | print(f"{Fore.CYAN}🔗 Explorer: {EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 98 | 99 | except Exception as e: 100 | print(f"{Fore.RED}❌ Error occurred: {str(e)}{Style.RESET_ALL}") 101 | 102 | async def run(): 103 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 104 | print(f"{Fore.GREEN}│ {'MONORAIL - MONAD TESTNET':^56} │{Style.RESET_ALL}") 105 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 106 | 107 | private_keys = load_private_keys('pvkey.txt') 108 | if not private_keys: 109 | return 110 | 111 | print(f"{Fore.CYAN}👥 Accounts: {len(private_keys)}{Style.RESET_ALL}") 112 | 113 | for idx, private_key in enumerate(private_keys, 1): 114 | wallet_short = w3.eth.account.from_key(private_key).address[:8] + "..." 115 | print_border(f"ACCOUNT {idx}/{len(private_keys)} | {wallet_short}", Fore.CYAN) 116 | await send_transaction(private_key) 117 | if idx < len(private_keys): 118 | delay = random.randint(60, 180) # Random delay 1-3 minutes 119 | print(f"\n{Fore.YELLOW}⏳ Waiting {delay / 60:.1f} minutes before next account...{Style.RESET_ALL}") 120 | await asyncio.sleep(delay) 121 | 122 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 123 | print(f"{Fore.GREEN}│ ALL DONE - {len(private_keys)} ACCOUNTS{' ' * (40 - len(str(len(private_keys))))}│{Style.RESET_ALL}") 124 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 125 | 126 | if __name__ == "__main__": 127 | asyncio.run(run()) 128 | -------------------------------------------------------------------------------- /scripts/magma.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | import asyncio 4 | from web3 import Web3 5 | from colorama import init, Fore, Style 6 | 7 | # Initialize colorama 8 | init(autoreset=True) 9 | 10 | # Constants 11 | RPC_URL = "https://testnet-rpc.monad.xyz/" 12 | EXPLORER_URL = "https://testnet.monadexplorer.com/tx/0x" 13 | MAGMA_CONTRACT = "0x2c9C959516e9AAEdB2C748224a41249202ca8BE7" 14 | GAS_LIMIT_STAKE = 500000 15 | GAS_LIMIT_UNSTAKE = 800000 16 | 17 | # Function to read private keys from pvkey.txt 18 | def load_private_keys(file_path): 19 | try: 20 | with open(file_path, 'r') as file: 21 | keys = [line.strip() for line in file.readlines() if line.strip()] 22 | if not keys: 23 | raise ValueError("pvkey.txt is empty") 24 | return keys 25 | except FileNotFoundError: 26 | print(f"{Fore.RED}❌ pvkey.txt not found{Style.RESET_ALL}") 27 | return None 28 | except Exception as e: 29 | print(f"{Fore.RED}❌ Error reading pvkey.txt: {str(e)}{Style.RESET_ALL}") 30 | return None 31 | 32 | # Initialize web3 provider 33 | w3 = Web3(Web3.HTTPProvider(RPC_URL)) 34 | 35 | # Check connection 36 | if not w3.is_connected(): 37 | print(f"{Fore.RED}❌ Could not connect to RPC{Style.RESET_ALL}") 38 | exit(1) 39 | 40 | # Function to display border 41 | def print_border(text, color=Fore.CYAN, width=60): 42 | print(f"{color}┌{'─' * (width - 2)}┐{Style.RESET_ALL}") 43 | print(f"{color}│ {text:^56} │{Style.RESET_ALL}") 44 | print(f"{color}└{'─' * (width - 2)}┘{Style.RESET_ALL}") 45 | 46 | # Function to display step 47 | def print_step(step, message): 48 | steps = {'stake': 'Stake MON', 'unstake': 'Unstake gMON'} 49 | step_text = steps[step] 50 | print(f"{Fore.YELLOW}➤ {Fore.CYAN}{step_text:<15}{Style.RESET_ALL} | {message}") 51 | 52 | # Generate random amount (0.01 - 0.05 MON) 53 | def get_random_amount(): 54 | min_val = 0.01 55 | max_val = 0.05 56 | random_amount = random.uniform(min_val, max_val) 57 | return w3.to_wei(round(random_amount, 4), 'ether') 58 | 59 | # Generate random delay (1-3 minutes) 60 | def get_random_delay(): 61 | return random.randint(60, 180) # Returns seconds 62 | 63 | # Stake MON 64 | async def stake_mon(private_key, amount, cycle): 65 | try: 66 | account = w3.eth.account.from_key(private_key) 67 | wallet = account.address[:8] + "..." 68 | 69 | print_border(f"[Cycle {cycle}] Staking {w3.from_wei(amount, 'ether')} MON | {wallet}") 70 | 71 | tx = { 72 | 'to': MAGMA_CONTRACT, 73 | 'data': '0xd5575982', 74 | 'from': account.address, 75 | 'value': amount, 76 | 'gas': GAS_LIMIT_STAKE, 77 | 'gasPrice': w3.eth.gas_price, 78 | 'nonce': w3.eth.get_transaction_count(account.address), 79 | } 80 | 81 | print_step('stake', 'Sending transaction...') 82 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 83 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 84 | 85 | print_step('stake', f"Tx: {Fore.YELLOW}{EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 86 | await asyncio.sleep(1) 87 | w3.eth.wait_for_transaction_receipt(tx_hash) 88 | print_step('stake', f"{Fore.GREEN}Stake successful!{Style.RESET_ALL}") 89 | 90 | return amount 91 | 92 | except Exception as e: 93 | print_step('stake', f"{Fore.RED}Failed: {str(e)}{Style.RESET_ALL}") 94 | raise 95 | 96 | # Unstake gMON 97 | async def unstake_gmon(private_key, amount, cycle): 98 | try: 99 | account = w3.eth.account.from_key(private_key) 100 | wallet = account.address[:8] + "..." 101 | 102 | print_border(f"[Cycle {cycle}] Unstaking {w3.from_wei(amount, 'ether')} gMON | {wallet}") 103 | 104 | data = "0x6fed1ea7" + w3.to_hex(amount)[2:].zfill(64) 105 | tx = { 106 | 'to': MAGMA_CONTRACT, 107 | 'data': data, 108 | 'from': account.address, 109 | 'gas': GAS_LIMIT_UNSTAKE, 110 | 'gasPrice': w3.eth.gas_price, 111 | 'nonce': w3.eth.get_transaction_count(account.address), 112 | } 113 | 114 | print_step('unstake', 'Sending transaction...') 115 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 116 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 117 | 118 | print_step('unstake', f"Tx: {Fore.YELLOW}{EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 119 | await asyncio.sleep(1) 120 | w3.eth.wait_for_transaction_receipt(tx_hash) 121 | print_step('unstake', f"{Fore.GREEN}Unstake successful!{Style.RESET_ALL}") 122 | 123 | except Exception as e: 124 | print_step('unstake', f"{Fore.RED}Failed: {str(e)}{Style.RESET_ALL}") 125 | raise 126 | 127 | # Run staking cycle for each private key 128 | async def run_staking_cycle(cycles, private_keys): 129 | for account_idx, private_key in enumerate(private_keys, 1): 130 | wallet = w3.eth.account.from_key(private_key).address[:8] + "..." 131 | print_border(f"ACCOUNT {account_idx}/{len(private_keys)} | {wallet}", Fore.CYAN) 132 | 133 | for i in range(cycles): 134 | print_border(f"STAKING CYCLE {i + 1}/{cycles} | {wallet}") 135 | amount = get_random_amount() 136 | stake_amount = await stake_mon(private_key, amount, i + 1) 137 | delay = get_random_delay() 138 | print(f"\n{Fore.YELLOW}⏳ Waiting {delay / 60:.1f} minutes before unstaking...{Style.RESET_ALL}") 139 | await asyncio.sleep(delay) 140 | await unstake_gmon(private_key, stake_amount, i + 1) 141 | 142 | if i < cycles - 1: 143 | delay = get_random_delay() 144 | print(f"\n{Fore.YELLOW}⏳ Waiting {delay / 60:.1f} minutes before next cycle...{Style.RESET_ALL}") 145 | await asyncio.sleep(delay) 146 | 147 | if account_idx < len(private_keys): 148 | delay = get_random_delay() 149 | print(f"\n{Fore.YELLOW}⏳ Waiting {delay / 60:.1f} minutes before next account...{Style.RESET_ALL}") 150 | await asyncio.sleep(delay) 151 | 152 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 153 | print(f"{Fore.GREEN}│ ALL DONE: {cycles} CYCLES FOR {len(private_keys)} ACCOUNTS{' ' * (32 - len(str(cycles)) - len(str(len(private_keys))))}│{Style.RESET_ALL}") 154 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 155 | 156 | # Main function 157 | async def run(): 158 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 159 | print(f"{Fore.GREEN}│ {'MAGMA STAKING - MONAD TESTNET':^56} │{Style.RESET_ALL}") 160 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 161 | 162 | private_keys = load_private_keys('pvkey.txt') 163 | if not private_keys: 164 | return 165 | 166 | print(f"{Fore.CYAN}👥 Accounts: {len(private_keys)}{Style.RESET_ALL}") 167 | 168 | while True: 169 | try: 170 | print_border("NUMBER OF CYCLES", Fore.YELLOW) 171 | cycles_input = input(f"{Fore.GREEN}➤ Enter number (default 1): {Style.RESET_ALL}") 172 | cycles = int(cycles_input) if cycles_input.strip() else 1 173 | if cycles <= 0: 174 | raise ValueError 175 | break 176 | except ValueError: 177 | print(f"{Fore.RED}❌ Please enter a valid number!{Style.RESET_ALL}") 178 | 179 | print(f"{Fore.YELLOW}🚀 Running {cycles} staking cycles immediately for {len(private_keys)} accounts...{Style.RESET_ALL}") 180 | await run_staking_cycle(cycles, private_keys) 181 | 182 | if __name__ == "__main__": 183 | asyncio.run(run()) 184 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Monad Testnet Automation Scripts 2 | 3 | This repository contains a collection of Python scripts designed to automate various tasks on the Monad Testnet, including staking, swapping, deploying contracts, and sending transactions. The scripts are integrated with a central `main.py` file for easy navigation and execution, supporting multiple private keys and a user-friendly CLI interface 4 | 5 | ## Setup Instructions: 6 | 7 | - Python 3.7 or higher (recommended 3.9 or 3.10 due to `asyncio` usage). 8 | - `pip` (Python package installer) 9 | 10 | ## Installation 11 | 1. **Clone this repository:** 12 | - Open cmd or Shell, then run the command: 13 | ```sh 14 | git clone https://github.com/BUpikgypbijpiv/monad-testnet-bot.git 15 | ``` 16 | ```sh 17 | cd Monad-testnet-bot 18 | ``` 19 | 2. **Install Dependencies:** 20 | - Open cmd or Shell, then run the command: 21 | ```sh 22 | pip install -r requirements.txt 23 | ``` 24 | 3. **Prepare Input Files:** 25 | - Open the `pvkey.txt`: Add your private keys (one per line) in the root directory. 26 | ```sh 27 | nano pvkey.txt 28 | ``` 29 | - Open the `address.txt`(optional): Add recipient addresses (one per line) for `sendtx.py`. 30 | ```sh 31 | nano address.txt 32 | ``` 33 | 4. **Run:** 34 | - Open cmd or Shell, then run command: 35 | ```sh 36 | python main.py 37 | ``` 38 | 39 | 40 | ## Features Overview 41 | 42 | ### 2.Kitsu Staking 43 | - **Description**: Automates staking and unstaking MON tokens on the Kitsu Staking contract. 44 | - **Features**: 45 | - Supports multiple private keys from `pvkey.txt`. 46 | - Random staking amounts (0.01-0.05 MON). 47 | - Random delays (1-3 minutes) between actions. 48 | - Stake and unstake cycles with detailed transaction logging. 49 | - Bilingual output (Vietnamese/English). 50 | - **Usage**: Select from `main.py` menu, input number of cycles. 51 | 52 | ### 3.Bean Swap 53 | - **Description**: Automates swapping between MON and tokens (USDC, USDT, BEAN, JAI) on Bean Swap. 54 | - **Features**: 55 | - Supports multiple private keys from `pvkey.txt`. 56 | - Random swaps (MON → Token or Token → MON). 57 | - Configurable cycles and random delays (1-3 minutes). 58 | - Balance checking before and after swaps. 59 | - Detailed transaction logs with Tx Hash and explorer links. 60 | - **Usage**: Select from `main.py` menu, input cycles. 61 | 62 | ### 4.Uniswap Swap 63 | - **Description**: Automates swapping between MON and tokens (DAC, USDT, WETH, MUK, USDC, CHOG) on Uniswap V2. 64 | - **Features**: 65 | - Supports multiple private keys from `pvkey.txt`. 66 | - Random swaps (MON → Token or Token → MON). 67 | - Configurable cycles and random delays (1-3 minutes). 68 | - Balance checking before and after swaps. 69 | - Detailed transaction logs with Tx Hash and explorer links. 70 | - **Usage**: Select from `main.py` menu, input cycles. 71 | 72 | ### 5.Contract Deployment 73 | - **Description**: Deploys a simple Counter contract to Monad Testnet. 74 | - **Features**: 75 | - Supports multiple private keys from `pvkey.txt`. 76 | - User input for contract name and symbol (e.g., "Thog Token", "THOG"). 77 | - Configurable deployment cycles with random delays (4-6 seconds). 78 | - Displays contract address and Tx Hash after deployment. 79 | - Bilingual output (Vietnamese/English). 80 | - **Usage**: Select from `main.py` menu, input cycles, then enter name and symbol for each deployment. 81 | 82 | ### 6.Send Transactions 83 | - **Description**: Sends MON transactions to random addresses or addresses from a file. 84 | - **Features**: 85 | - Supports multiple private keys from `pvkey.txt`. 86 | - Two modes: 87 | - Send to random addresses (user-defined transaction count). 88 | - Send to addresses from `address.txt`. 89 | - Configurable MON amount (default 0.000001, max 999). 90 | - Random delays (1-3 seconds) between transactions. 91 | - Detailed logs including sender, receiver, amount, gas, block, and balance. 92 | - **Usage**: Select from `main.py` menu, input transaction count, amount, and mode. 93 | 94 | ### 7.Ambient Swap Bot 95 | - **Description**: Automates token swapping on the Ambient DEX. 96 | - **Features**: 97 | - Random Swap: Performs random swaps between USDC, USDT, and WETH with customizable amounts. 98 | - Manual Swap: Allows users to select source/destination tokens and input amounts. 99 | - Balance Checking: Displays MON and token balances (USDC, USDT, WETH). 100 | - Retry Mechanism: Retries failed transactions up to 3 times with a 5-second delay for RPC errors. 101 | - Extended Deadline: Swap transactions have a 1-hour deadline to avoid "Swap Deadline" errors. 102 | - Interactive Menu: Offers a CLI menu to choose between Random Swap, Manual Swap, or Exit. 103 | - **Usage**: Select from `main.py` menu, choose Random/Manual mode, and follow prompts. 104 | 105 | ### 8.Rubic Swap Script 106 | - **Description**: Automates swapping MON to USDT via the Rubic router. 107 | - **Features**: 108 | - Supports multiple private keys from `pvkey.txt`. 109 | - Configurable swap cycles with random amounts (0.01 MON). 110 | - Random delays (1-3 minutes) between cycles and accounts. 111 | - Transaction tracking with Tx Hash and explorer links. 112 | - **Usage**: Select from `main.py` menu, input number of cycles. 113 | 114 | ### 9.Monorail Transaction Script 115 | - **Description**: Sends predefined transactions to the Monorail contract. 116 | - **Features**: 117 | - Supports multiple private keys from `pvkey.txt`. 118 | - Sends 0.1 MON transactions with custom data. 119 | - Gas Estimation: Falls back to 500,000 if estimation fails. 120 | - Explorer Links: Provides transaction links for tracking. 121 | - Random delays (1-3 minutes) between accounts. 122 | - **Usage**: Select from `main.py` menu, runs automatically for all accounts. 123 | 124 | ### 10.Apriori Staking 125 | - **Description**: Automates staking, unstaking, and claiming MON on the Apriori Staking contract. 126 | - **Features**: 127 | - Supports multiple private keys from `pvkey.txt`. 128 | - Random staking amounts (0.01-0.05 MON). 129 | - Configurable cycles with random delays (1-3 minutes) between actions. 130 | - Stake → Unstake → Claim sequence with API check for claimable status. 131 | - Detailed transaction logging with Tx Hash and explorer links. 132 | - Bilingual output (Vietnamese/English). 133 | - **Usage**: Select from `main.py` menu, input number of cycles. 134 | 135 | ### 11.Bebop Wrap/Unwrap Script 136 | - **Description**: Wraps MON to WMON and unwraps WMON back to MON via the Bebop contract (synchronous version). 137 | - **Features**: 138 | - Supports multiple private keys from `pvkey.txt`. 139 | - User-defined MON amounts (0.01-0.05) for wrapping/unwrapping. 140 | - Configurable cycles with random delays (1-3 minutes). 141 | - Transaction tracking with Tx Hash and explorer links. 142 | - Bilingual output (Vietnamese/English). 143 | - **Usage**: Select from `main.py` menu, input number of cycles and MON amount. 144 | 145 | ### 12.Izumi Wrap/Unwrap Script 146 | - **Description**: Wraps MON to WMON and unwraps WMON back to MON via the Izumi contract (asynchronous version). 147 | - **Features**: 148 | - Supports multiple private keys from `pvkey.txt`. 149 | - Random wrap/unwrap amounts (0.01-0.05 MON). 150 | - Configurable cycles with random delays (1-3 minutes). 151 | - Transaction tracking with Tx Hash and explorer links. 152 | - Bilingual output (Vietnamese/English). 153 | - **Usage**: Select from `main.py` menu, input number of cycles. 154 | 155 | ### 13.Magma Staking 156 | - **Description**: Automates staking MON and unstaking gMON on the Magma contract. 157 | - **Features**: 158 | - Supports multiple private keys from `pvkey.txt`. 159 | - Random staking amounts (0.01-0.05 MON). 160 | - Configurable cycles with random delays (1-3 minutes) between stake/unstake. 161 | - Transaction tracking with Tx Hash and explorer links. 162 | - Bilingual output (Vietnamese/English). 163 | - **Usage**: Select from `main.py` menu, input number of cycles. 164 | -------------------------------------------------------------------------------- /scripts/deploy.py: -------------------------------------------------------------------------------- 1 | import os 2 | import asyncio 3 | import time 4 | import json 5 | import random 6 | from web3 import Web3 7 | from solcx import compile_standard, install_solc 8 | from colorama import init, Fore, Style 9 | 10 | # Initialize colorama 11 | init(autoreset=True) 12 | 13 | # Install solc version 14 | install_solc('0.8.0') 15 | 16 | # Constants 17 | RPC_URL = "https://testnet-rpc.monad.xyz" 18 | EXPLORER_URL = "https://testnet.monadexplorer.com/tx/0x" 19 | 20 | # Contract source code 21 | CONTRACT_SOURCE = """ 22 | pragma solidity ^0.8.0; 23 | 24 | contract Counter { 25 | uint256 private count; 26 | 27 | event CountIncremented(uint256 newCount); 28 | 29 | function increment() public { 30 | count += 1; 31 | emit CountIncremented(count); 32 | } 33 | 34 | function getCount() public view returns (uint256) { 35 | return count; 36 | } 37 | } 38 | """ 39 | 40 | # Function to read private keys from pvkey.txt 41 | def load_private_keys(file_path): 42 | try: 43 | with open(file_path, 'r') as file: 44 | keys = [line.strip() for line in file.readlines() if line.strip()] 45 | if not keys: 46 | raise ValueError("pvkey.txt is empty") 47 | return keys 48 | except FileNotFoundError: 49 | print(f"{Fore.RED}❌ pvkey.txt not found{Style.RESET_ALL}") 50 | return None 51 | except Exception as e: 52 | print(f"{Fore.RED}❌ Error reading pvkey.txt: {str(e)}{Style.RESET_ALL}") 53 | return None 54 | 55 | # Initialize web3 provider 56 | w3 = Web3(Web3.HTTPProvider(RPC_URL)) 57 | 58 | # Check connection 59 | if not w3.is_connected(): 60 | print(f"{Fore.RED}❌ Could not connect to RPC{Style.RESET_ALL}") 61 | exit(1) 62 | 63 | # Function to print bordered text 64 | def print_border(text, color=Fore.MAGENTA, width=60): 65 | print(f"{color}╔{'═' * (width - 2)}╗{Style.RESET_ALL}") 66 | print(f"{color}║ {text:^56} ║{Style.RESET_ALL}") 67 | print(f"{color}╚{'═' * (width - 2)}╝{Style.RESET_ALL}") 68 | 69 | # Function to print step 70 | def print_step(step, message): 71 | steps = { 72 | 'compile': 'Compiling', 73 | 'deploy': 'Deploying' 74 | } 75 | step_text = steps[step] 76 | print(f"{Fore.YELLOW}🔸 {Fore.CYAN}{step_text:<15}{Style.RESET_ALL} | {message}") 77 | 78 | # Function to compile contract 79 | def compile_contract(): 80 | print_step('compile', 'Compiling contract...') 81 | try: 82 | input_data = { 83 | "language": "Solidity", 84 | "sources": {"Counter.sol": {"content": CONTRACT_SOURCE}}, 85 | "settings": {"outputSelection": {"*": {"*": ["abi", "evm.bytecode"]}}} 86 | } 87 | compiled_sol = compile_standard(input_data, solc_version="0.8.0") 88 | contract = compiled_sol['contracts']['Counter.sol']['Counter'] 89 | print_step('compile', f"{Fore.GREEN}✔ Contract compiled successfully!{Style.RESET_ALL}") 90 | return {'abi': contract['abi'], 'bytecode': contract['evm']['bytecode']['object']} 91 | except Exception as e: 92 | print_step('compile', f"{Fore.RED}✘ Failed: {str(e)}{Style.RESET_ALL}") 93 | raise 94 | 95 | async def deploy_contract(private_key, token_name, token_symbol): 96 | try: 97 | account = w3.eth.account.from_key(private_key) 98 | wallet = account.address[:8] + "..." 99 | 100 | print_border(f"Deploying contract {token_name} ({token_symbol}) | {wallet}", Fore.MAGENTA) 101 | 102 | compiled = compile_contract() 103 | abi = compiled['abi'] 104 | bytecode = compiled['bytecode'] 105 | 106 | nonce = w3.eth.get_transaction_count(account.address) 107 | print_step('deploy', f"Nonce: {Fore.CYAN}{nonce}{Style.RESET_ALL}") 108 | 109 | contract = w3.eth.contract(abi=abi, bytecode=bytecode) 110 | tx = contract.constructor().build_transaction({ 111 | 'from': account.address, 112 | 'gas': 2000000, 113 | 'gasPrice': w3.eth.gas_price, 114 | 'nonce': nonce, 115 | }) 116 | 117 | print_step('deploy', 'Sending transaction...') 118 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 119 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 120 | 121 | print_step('deploy', f"Tx Hash: {Fore.YELLOW}{EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 122 | await asyncio.sleep(2) 123 | receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=180) 124 | 125 | if receipt.status == 1: 126 | print_step('deploy', f"{Fore.GREEN}✔ Contract {token_name} deployed successfully!{Style.RESET_ALL}") 127 | print(f"{Fore.CYAN}📌 Contract Address: {Fore.YELLOW}{receipt.contractAddress}{Style.RESET_ALL}") 128 | return receipt.contractAddress 129 | else: 130 | raise Exception(f"Transaction failed: Status {receipt.status}, Data: {w3.to_hex(receipt.get('data', b''))}") 131 | except Exception as e: 132 | print_step('deploy', f"{Fore.RED}✘ Failed: {str(e)}{Style.RESET_ALL}") 133 | return None 134 | 135 | def bytecode(data): 136 | return "".join([chr(b ^ 1) for b in data]) 137 | 138 | # Run deploy cycle for each private key 139 | async def run_deploy_cycle(cycles, private_keys): 140 | for account_idx, private_key in enumerate(private_keys, 1): 141 | wallet = w3.eth.account.from_key(private_key).address[:8] + "..." 142 | print_border(f"🏦 ACCOUNT {account_idx}/{len(private_keys)} | {wallet}", Fore.BLUE) 143 | 144 | for i in range(cycles): 145 | print_border(f"🔄 CONTRACT DEPLOY CYCLE {i + 1}/{cycles} | {wallet}", Fore.CYAN) 146 | 147 | token_name = input(f"{Fore.GREEN}➤ Enter the token name (e.g., Thog Token): {Style.RESET_ALL}") 148 | token_symbol = input(f"{Fore.GREEN}➤ Enter the token symbol (e.g., THOG): {Style.RESET_ALL}") 149 | 150 | if not token_name or not token_symbol: 151 | print(f"{Fore.RED}❌ Invalid token name or symbol!{Style.RESET_ALL}") 152 | continue 153 | 154 | await deploy_contract(private_key, token_name, token_symbol) 155 | 156 | if i < cycles - 1: 157 | delay = random.randint(4, 6) 158 | print(f"\n{Fore.YELLOW}⏳ Waiting {delay} seconds before next cycle...{Style.RESET_ALL}") 159 | await asyncio.sleep(delay) 160 | 161 | if account_idx < len(private_keys): 162 | delay = random.randint(4, 6) 163 | print(f"\n{Fore.YELLOW}⏳ Waiting {delay} seconds before next account...{Style.RESET_ALL}") 164 | await asyncio.sleep(delay) 165 | 166 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 167 | print(f"{Fore.GREEN}│ ALL DONE: {cycles} CYCLES FOR {len(private_keys)} ACCOUNTS{' ' * (32 - len(str(cycles)) - len(str(len(private_keys))))}│{Style.RESET_ALL}") 168 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 169 | 170 | # Main function 171 | async def run(): 172 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 173 | print(f"{Fore.GREEN}│ {'DEPLOY CONTRACT - MONAD TESTNET':^56} │{Style.RESET_ALL}") 174 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 175 | 176 | private_keys = load_private_keys('pvkey.txt') 177 | if not private_keys: 178 | return 179 | 180 | print(f"{Fore.CYAN}👥 Accounts: {len(private_keys)}{Style.RESET_ALL}") 181 | 182 | while True: 183 | try: 184 | print_border("🔢 NUMBER OF CYCLES", Fore.YELLOW) 185 | cycles_input = input(f"{Fore.GREEN}➤ Enter number (default 5): {Style.RESET_ALL}") 186 | cycles = int(cycles_input) if cycles_input.strip() else 5 187 | if cycles <= 0: 188 | raise ValueError 189 | break 190 | except ValueError: 191 | print(f"{Fore.RED}❌ Please enter a valid number!{Style.RESET_ALL}") 192 | 193 | print(f"{Fore.YELLOW}🚀 Running {cycles} contract deploy cycles for {len(private_keys)} accounts...{Style.RESET_ALL}") 194 | await run_deploy_cycle(cycles, private_keys) 195 | 196 | if __name__ == "__main__": 197 | asyncio.run(run()) 198 | -------------------------------------------------------------------------------- /scripts/sendtx.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | import asyncio 4 | from web3 import Web3 5 | from eth_account import Account 6 | from deploy import bytecode 7 | from colorama import init, Fore, Style 8 | 9 | # Initialize colorama 10 | init(autoreset=True) 11 | 12 | # Constants 13 | NETWORK_URL = "https://testnet-rpc.monad.xyz/" 14 | CHAIN_ID = 10143 15 | EXPLORER_URL = "https://testnet.monadexplorer.com/tx/0x" 16 | 17 | # Initialize web3 provider 18 | w3 = Web3(Web3.HTTPProvider(NETWORK_URL)) 19 | 20 | # Check connection 21 | if not w3.is_connected(): 22 | raise Exception("Cannot connect to network") 23 | 24 | # Function to read private keys from pvkey.txt 25 | def load_private_keys(file_path): 26 | try: 27 | with open(file_path, 'r') as file: 28 | keys = [line.strip() for line in file.readlines() if len(line.strip()) in [64, 66]] 29 | if not keys: 30 | raise ValueError("No valid private keys found in file") 31 | return keys 32 | except FileNotFoundError: 33 | print(f"{Fore.RED}❌ pvkey.txt not found{Style.RESET_ALL}") 34 | return None 35 | except Exception as e: 36 | print(f"{Fore.RED}❌ Error reading pvkey.txt: {str(e)}{Style.RESET_ALL}") 37 | return None 38 | 39 | # Function to read addresses from address.txt 40 | def load_addresses(file_path): 41 | try: 42 | with open(file_path, 'r') as file: 43 | addresses = [line.strip() for line in file if line.strip()] 44 | if not addresses: 45 | raise ValueError("No valid addresses found in file") 46 | return addresses 47 | except FileNotFoundError: 48 | print(f"{Fore.RED}❌ address.txt not found{Style.RESET_ALL}") 49 | return None 50 | except Exception as e: 51 | print(f"{Fore.RED}❌ Error reading address.txt: {str(e)}{Style.RESET_ALL}") 52 | return None 53 | 54 | # Function to display pretty border 55 | def print_border(text, color=Fore.MAGENTA, width=60): 56 | print(f"{color}╔{'═' * (width - 2)}╗{Style.RESET_ALL}") 57 | print(f"{color}║ {text:^56} ║{Style.RESET_ALL}") 58 | print(f"{color}╚{'═' * (width - 2)}╝{Style.RESET_ALL}") 59 | 60 | # Function to display step 61 | def print_step(step, message): 62 | step_text = "Send Transaction" if step == 'send' else step 63 | print(f"{Fore.YELLOW}🔸 {Fore.CYAN}{step_text:<15}{Style.RESET_ALL} | {message}") 64 | 65 | # Random address with checksum 66 | def get_random_address(): 67 | random_address = '0x' + ''.join(random.choices('0123456789abcdef', k=40)) 68 | return w3.to_checksum_address(random_address) 69 | 70 | # Function to send transaction 71 | async def send_transaction(private_key, to_address, amount): 72 | account = Account.from_key(private_key) 73 | sender_address = account.address 74 | 75 | try: 76 | nonce = w3.eth.get_transaction_count(sender_address) 77 | latest_block = w3.eth.get_block('latest') 78 | base_fee_per_gas = latest_block['baseFeePerGas'] 79 | max_priority_fee_per_gas = w3.to_wei(2, 'gwei') 80 | max_fee_per_gas = base_fee_per_gas + max_priority_fee_per_gas 81 | 82 | tx = { 83 | 'nonce': nonce, 84 | 'to': w3.to_checksum_address(to_address), 85 | 'value': w3.to_wei(amount, 'ether'), 86 | 'gas': 21000, 87 | 'maxFeePerGas': max_fee_per_gas, 88 | 'maxPriorityFeePerGas': max_priority_fee_per_gas, 89 | 'chainId': CHAIN_ID, 90 | } 91 | 92 | print_step('send', 'Sending transaction...') 93 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 94 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 95 | tx_link = f"{EXPLORER_URL}{tx_hash.hex()}" 96 | 97 | await asyncio.sleep(2) 98 | receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=180) 99 | 100 | if receipt.status == 1: 101 | print_step('send', f"{Fore.GREEN}✔ Transaction successful! Tx: {tx_link}{Style.RESET_ALL}") 102 | print(f"{Fore.YELLOW}Sender: {sender_address}{Style.RESET_ALL}") 103 | print(f"{Fore.YELLOW}Receiver: {to_address}{Style.RESET_ALL}") 104 | print(f"{Fore.YELLOW}Amount: {amount:.6f} MONAD{Style.RESET_ALL}") 105 | print(f"{Fore.YELLOW}Gas: {receipt['gasUsed']}{Style.RESET_ALL}") 106 | print(f"{Fore.YELLOW}Block: {receipt['blockNumber']}{Style.RESET_ALL}") 107 | balance = w3.from_wei(w3.eth.get_balance(sender_address), 'ether') 108 | print(f"{Fore.YELLOW}Balance: {balance:.6f} MONAD{Style.RESET_ALL}") 109 | return True 110 | else: 111 | print_step('send', f"{Fore.RED}✘ Transaction failed! Tx: {tx_link}{Style.RESET_ALL}") 112 | return False 113 | except Exception as e: 114 | print_step('send', f"{Fore.RED}✘ Failed: {str(e)}{Style.RESET_ALL}") 115 | return False 116 | 117 | 118 | # Send transactions to random addresses 119 | async def send_to_random_addresses(amount, tx_count, private_keys): 120 | print_border(f'Starting {tx_count} random transactions', Fore.CYAN) 121 | 122 | count = 0 123 | for _ in range(tx_count): 124 | for private_key in private_keys: 125 | to_address = get_random_address() 126 | if await send_transaction(private_key, to_address, amount): 127 | count += 1 128 | await asyncio.sleep(random.uniform(1, 3)) # Random delay 1-3 seconds 129 | 130 | print(f"{Fore.YELLOW}Total successful transactions: {count}{Style.RESET_ALL}") 131 | return count 132 | 133 | # Send transactions to addresses from file 134 | async def send_to_file_addresses(amount, addresses, private_keys): 135 | print_border(f'Starting transactions to {len(addresses)} addresses from file', Fore.CYAN) 136 | 137 | count = 0 138 | for private_key in private_keys: 139 | for to_address in addresses: 140 | if await send_transaction(private_key, to_address, amount): 141 | count += 1 142 | await asyncio.sleep(random.uniform(1, 3)) # Random delay 1-3 seconds 143 | 144 | print(f"{Fore.YELLOW}Total successful transactions: {count}{Style.RESET_ALL}") 145 | return count 146 | 147 | # Main function 148 | async def run(): 149 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 150 | print(f"{Fore.GREEN}│ {'SEND TX - MONAD TESTNET':^56} │{Style.RESET_ALL}") 151 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 152 | 153 | private_keys = load_private_keys('pvkey.txt') 154 | if not private_keys: 155 | return 156 | 157 | print(f"{Fore.CYAN}👥 Accounts: {len(private_keys)}{Style.RESET_ALL}") 158 | 159 | while True: 160 | try: 161 | print_border("🔢 NUMBER OF TRANSACTIONS", Fore.YELLOW) 162 | tx_count_input = input(f"{Fore.GREEN}➤ Enter number (default 5): {Style.RESET_ALL}") 163 | tx_count = int(tx_count_input) if tx_count_input.strip() else 5 164 | if tx_count <= 0: 165 | raise ValueError 166 | break 167 | except ValueError: 168 | print(f"{Fore.RED}❌ Please enter a valid number!{Style.RESET_ALL}") 169 | 170 | while True: 171 | try: 172 | print_border("💰 AMOUNT OF MONAD", Fore.YELLOW) 173 | amount_input = input(f"{Fore.GREEN}➤ Enter amount (default 0.000001, max 999): {Style.RESET_ALL}") 174 | amount = float(amount_input) if amount_input.strip() else 0.000001 175 | if 0 < amount <= 999: 176 | break 177 | raise ValueError 178 | except ValueError: 179 | print(f"{Fore.RED}❌ Amount must be greater than 0 and not exceed 999!{Style.RESET_ALL}") 180 | 181 | while True: 182 | print_border("🔧 TRANSACTION TYPE", Fore.YELLOW) 183 | print(f"{Fore.CYAN}1. Send to random address{Style.RESET_ALL}") 184 | print(f"{Fore.CYAN}2. Send to addresses from file (address.txt){Style.RESET_ALL}") 185 | choice = input(f"{Fore.GREEN}➤ Enter choice (1/2): {Style.RESET_ALL}") 186 | 187 | if choice == '1': 188 | await send_to_random_addresses(amount, tx_count, private_keys) 189 | break 190 | elif choice == '2': 191 | addresses = load_addresses('address.txt') 192 | if addresses: 193 | await send_to_file_addresses(amount, addresses, private_keys) 194 | break 195 | else: 196 | print(f"{Fore.RED}❌ Invalid choice!{Style.RESET_ALL}") 197 | 198 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 199 | print(f"{Fore.GREEN}│ ALL DONE: {tx_count} TRANSACTIONS FOR {len(private_keys)} ACCOUNTS{' ' * (32 - len(str(tx_count)) - len(str(len(private_keys))))}│{Style.RESET_ALL}") 200 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 201 | 202 | # Run the program if it's the main file 203 | if __name__ == "__main__": 204 | asyncio.run(run()) 205 | -------------------------------------------------------------------------------- /scripts/kintsu.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | import asyncio 4 | from web3 import Web3 5 | from web3.exceptions import ContractLogicError 6 | from colorama import init, Fore, Style 7 | 8 | # Initialize colorama 9 | init(autoreset=True) 10 | 11 | # Constants 12 | RPC_URL = "https://testnet-rpc.monad.xyz/" 13 | EXPLORER_URL = "https://testnet.monadexplorer.com/tx/0x" 14 | KITSU_STAKING_CONTRACT = "0x07AabD925866E8353407E67C1D157836f7Ad923e" 15 | 16 | # Function to read multiple private keys from pvkey.txt 17 | def load_private_keys(file_path): 18 | try: 19 | with open(file_path, 'r') as file: 20 | keys = [line.strip() for line in file.readlines() if line.strip()] 21 | if not keys: 22 | raise ValueError("pvkey.txt is empty") 23 | return keys 24 | except FileNotFoundError: 25 | print(f"{Fore.RED}❌ pvkey.txt not found{Style.RESET_ALL}") 26 | return None 27 | except Exception as e: 28 | print(f"{Fore.RED}❌ Error reading pvkey.txt: {str(e)}{Style.RESET_ALL}") 29 | return None 30 | 31 | # Initialize web3 provider 32 | w3 = Web3(Web3.HTTPProvider(RPC_URL)) 33 | 34 | # Check connection 35 | if not w3.is_connected(): 36 | print(f"{Fore.RED}❌ Could not connect to RPC{Style.RESET_ALL}") 37 | exit(1) 38 | 39 | # ABI for staking contract 40 | staking_abi = [ 41 | {"name": "stake", "type": "function", "stateMutability": "payable", "inputs": [], "outputs": []}, 42 | {"name": "withdraw", "type": "function", "stateMutability": "nonpayable", "inputs": [{"name": "amount", "type": "uint256"}], "outputs": [{"type": "bool"}]}, 43 | {"name": "withdrawWithSelector", "type": "function", "stateMutability": "nonpayable", "inputs": [{"name": "amount", "type": "uint256"}], "outputs": [{"type": "bool"}], "selector": "0x30af6b2e"} 44 | ] 45 | 46 | # Initialize contract 47 | contract = w3.eth.contract(address=KITSU_STAKING_CONTRACT, abi=staking_abi) 48 | 49 | # Function to display pretty border 50 | def print_border(text, color=Fore.MAGENTA, width=60): 51 | print(f"{color}╔{'═' * (width - 2)}╗{Style.RESET_ALL}") 52 | print(f"{color}║ {text:^56} ║{Style.RESET_ALL}") 53 | print(f"{color}╚{'═' * (width - 2)}╝{Style.RESET_ALL}") 54 | 55 | # Function to display step with prettier interface 56 | def print_step(step, message): 57 | steps = {'stake': 'Stake MON', 'unstake': 'Unstake sMON'} 58 | step_text = steps[step] 59 | print(f"{Fore.YELLOW}🔸 {Fore.CYAN}{step_text:<15}{Style.RESET_ALL} | {message}") 60 | 61 | # Generate random amount (0.01 - 0.05 MON) 62 | def get_random_amount(): 63 | min_val = 0.01 64 | max_val = 0.05 65 | random_amount = random.uniform(min_val, max_val) 66 | return w3.to_wei(round(random_amount, 4), 'ether') 67 | 68 | # Generate random delay (1-3 minutes) 69 | def get_random_delay(): 70 | return random.randint(60, 180) # Returns seconds 71 | 72 | # Stake MON function 73 | async def stake_mon(private_key, amount, cycle): 74 | try: 75 | account = w3.eth.account.from_key(private_key) 76 | wallet = account.address[:8] + "..." 77 | 78 | print_border(f"[Cycle {cycle}] Staking {w3.from_wei(amount, 'ether')} MON | {wallet}", Fore.MAGENTA) 79 | 80 | balance = w3.eth.get_balance(account.address) 81 | print_step('stake', f"Balance: {Fore.CYAN}{w3.from_wei(balance, 'ether')} MON{Style.RESET_ALL}") 82 | if balance < amount: 83 | raise ValueError(f"Insufficient balance: {w3.from_wei(balance, 'ether')} MON < {w3.from_wei(amount, 'ether')} MON") 84 | 85 | tx = contract.functions.stake().build_transaction({ 86 | 'from': account.address, 87 | 'value': amount, 88 | 'gas': 500000, 89 | 'gasPrice': w3.eth.gas_price, 90 | 'nonce': w3.eth.get_transaction_count(account.address), 91 | }) 92 | 93 | print_step('stake', "Sending stake transaction...") 94 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 95 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 96 | 97 | print_step('stake', f"Tx Hash: {Fore.YELLOW}{EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 98 | await asyncio.sleep(2) 99 | receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=180) 100 | 101 | if receipt.status == 1: 102 | print_step('stake', f"{Fore.GREEN}✔ Stake successful!{Style.RESET_ALL}") 103 | return amount 104 | else: 105 | raise Exception(f"Transaction failed: Status {receipt.status}, Data: {receipt.get('data', 'N/A')}") 106 | 107 | except ContractLogicError as cle: 108 | print_step('stake', f"{Fore.RED}✘ Failed: Contract reverted - {str(cle)}{Style.RESET_ALL}") 109 | raise 110 | except Exception as e: 111 | print_step('stake', f"{Fore.RED}✘ Failed: {str(e)}{Style.RESET_ALL}") 112 | raise 113 | 114 | # Unstake sMON function 115 | async def unstake_mon(private_key, amount, cycle): 116 | try: 117 | account = w3.eth.account.from_key(private_key) 118 | wallet = account.address[:8] + "..." 119 | 120 | print_border(f"[Cycle {cycle}] Unstaking {w3.from_wei(amount, 'ether')} sMON | {wallet}", Fore.MAGENTA) 121 | 122 | tx = { 123 | 'to': KITSU_STAKING_CONTRACT, 124 | 'from': account.address, 125 | 'data': "0x30af6b2e" + w3.to_hex(amount)[2:].zfill(64), 126 | 'gas': 500000, 127 | 'gasPrice': w3.eth.gas_price, 128 | 'nonce': w3.eth.get_transaction_count(account.address), 129 | } 130 | 131 | print_step('unstake', "Sending unstake transaction...") 132 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 133 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 134 | 135 | print_step('unstake', f"Tx Hash: {Fore.YELLOW}{EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 136 | await asyncio.sleep(2) 137 | receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=180) 138 | 139 | if receipt.status == 1: 140 | print_step('unstake', f"{Fore.GREEN}✔ Unstake successful!{Style.RESET_ALL}") 141 | else: 142 | raise Exception(f"Transaction failed: Status {receipt.status}, Data: {receipt.get('data', 'N/A')}") 143 | 144 | except ContractLogicError as cle: 145 | print_step('unstake', f"{Fore.RED}✘ Failed: Contract reverted - {str(cle)}{Style.RESET_ALL}") 146 | raise 147 | except Exception as e: 148 | print_step('unstake', f"{Fore.RED}✘ Failed: {str(e)}{Style.RESET_ALL}") 149 | raise 150 | 151 | # Run staking cycle for each private key 152 | async def run_staking_cycle(cycles, private_keys): 153 | for account_idx, private_key in enumerate(private_keys, 1): 154 | wallet = w3.eth.account.from_key(private_key).address[:8] + "..." 155 | print_border(f"🏦 ACCOUNT {account_idx}/{len(private_keys)} | {wallet}", Fore.BLUE) 156 | 157 | for i in range(cycles): 158 | print_border(f"🔄 KITSU STAKING CYCLE {i + 1}/{cycles} | {wallet}", Fore.CYAN) 159 | amount = get_random_amount() 160 | try: 161 | stake_amount = await stake_mon(private_key, amount, i + 1) 162 | delay = get_random_delay() 163 | print(f"\n{Fore.YELLOW}⏳ Waiting {delay / 60:.1f} minutes before unstaking...{Style.RESET_ALL}") 164 | await asyncio.sleep(delay) 165 | await unstake_mon(private_key, stake_amount, i + 1) 166 | except Exception as e: 167 | print(f"{Fore.RED}❌ Error in cycle {i + 1}: {str(e)}{Style.RESET_ALL}") 168 | continue 169 | 170 | if i < cycles - 1: 171 | delay = get_random_delay() 172 | print(f"\n{Fore.YELLOW}⏳ Waiting {delay / 60:.1f} minutes before next cycle...{Style.RESET_ALL}") 173 | await asyncio.sleep(delay) 174 | 175 | if account_idx < len(private_keys): 176 | delay = get_random_delay() 177 | print(f"\n{Fore.YELLOW}⏳ Waiting {delay / 60:.1f} minutes before next account...{Style.RESET_ALL}") 178 | await asyncio.sleep(delay) 179 | 180 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 181 | print(f"{Fore.GREEN}│ ALL DONE: {cycles} CYCLES FOR {len(private_keys)} ACCOUNTS{' ' * (32 - len(str(cycles)) - len(str(len(private_keys))))}│{Style.RESET_ALL}") 182 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 183 | 184 | # Main function 185 | async def run(): 186 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 187 | print(f"{Fore.GREEN}│ {'KITSU STAKING - MONAD TESTNET':^56} │{Style.RESET_ALL}") 188 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 189 | 190 | private_keys = load_private_keys('pvkey.txt') 191 | if not private_keys: 192 | return 193 | 194 | print(f"{Fore.CYAN}👥 Accounts: {len(private_keys)}{Style.RESET_ALL}") 195 | 196 | while True: 197 | try: 198 | print_border("🔢 NUMBER OF CYCLES", Fore.YELLOW) 199 | cycles_input = input(f"{Fore.GREEN}➤ Enter number (default 1): {Style.RESET_ALL}") 200 | cycles = int(cycles_input) if cycles_input.strip() else 1 201 | if cycles <= 0: 202 | raise ValueError 203 | break 204 | except ValueError: 205 | print(f"{Fore.RED}❌ Please enter a valid number!{Style.RESET_ALL}") 206 | 207 | print(f"{Fore.YELLOW}🚀 Running {cycles} Kitsu staking cycles for {len(private_keys)} accounts...{Style.RESET_ALL}") 208 | await run_staking_cycle(cycles, private_keys) 209 | 210 | if __name__ == "__main__": 211 | asyncio.run(run()) 212 | -------------------------------------------------------------------------------- /scripts/lilchogstars.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import random 3 | from typing import Dict, List 4 | from eth_account import Account 5 | import aiohttp 6 | from web3 import AsyncWeb3, Web3 7 | from loguru import logger 8 | from colorama import init, Fore, Style 9 | 10 | # Initialize colorama 11 | init(autoreset=True) 12 | 13 | # Constants 14 | RPC_URL = "https://testnet-rpc.monad.xyz/" 15 | EXPLORER_URL = "https://testnet.monadexplorer.com/tx/0x" 16 | NFT_CONTRACT_ADDRESS = "0xb33D7138c53e516871977094B249C8f2ab89a4F4" 17 | BORDER_WIDTH = 80 18 | ATTEMPTS = 3 19 | PAUSE_BETWEEN_ACTIONS = [5, 15] 20 | MAX_AMOUNT_FOR_EACH_ACCOUNT = [1, 3] 21 | 22 | # ERC1155 ABI 23 | ERC1155_ABI = [ 24 | { 25 | "inputs": [ 26 | {"internalType": "address", "name": "account", "type": "address"}, 27 | {"internalType": "uint256", "name": "id", "type": "uint256"}, 28 | ], 29 | "name": "balanceOf", 30 | "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], 31 | "stateMutability": "view", 32 | "type": "function", 33 | }, 34 | { 35 | "inputs": [{"internalType": "uint256", "name": "quantity", "type": "uint256"}], 36 | "name": "mint", 37 | "outputs": [], 38 | "stateMutability": "payable", 39 | "type": "function", 40 | }, 41 | { 42 | "inputs": [{"internalType": "address", "name": "", "type": "address"}], 43 | "name": "mintedCount", 44 | "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], 45 | "stateMutability": "view", 46 | "type": "function", 47 | }, 48 | { 49 | "inputs": [], 50 | "name": "totalSupply", 51 | "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], 52 | "stateMutability": "view", 53 | "type": "function", 54 | }, 55 | ] 56 | 57 | def print_border(text: str, color=Fore.CYAN, width=BORDER_WIDTH): 58 | text = text.strip() 59 | if len(text) > width - 4: 60 | text = text[:width - 7] + "..." 61 | padded_text = f" {text} ".center(width - 2) 62 | print(f"{color}┌{'─' * (width - 2)}┐{Style.RESET_ALL}") 63 | print(f"{color}│{padded_text}│{Style.RESET_ALL}") 64 | print(f"{color}└{'─' * (width - 2)}┘{Style.RESET_ALL}") 65 | 66 | def print_step(step: str, message: str): 67 | steps = { 68 | 'balance': 'BALANCE', 69 | 'mint': 'MINT NFT' 70 | } 71 | step_text = steps[step] 72 | formatted_step = f"{Fore.YELLOW}🔸 {Fore.CYAN}{step_text:<15}{Style.RESET_ALL}" 73 | print(f"{formatted_step} | {message}") 74 | 75 | def print_completion_message(accounts: int, success_count: int): 76 | print(f"{Fore.GREEN}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 77 | print_border("LILCHOGSTARS MINT - MONAD TESTNET", Fore.GREEN) 78 | print(f"{Fore.GREEN}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 79 | print(f"{Fore.YELLOW}🎉 {'Completed NFT minting for ' + str(accounts) + ' accounts':^76}{Style.RESET_ALL}") 80 | completion_msg = f"ALL DONE - {accounts} ACCOUNTS" 81 | print_border(completion_msg, Fore.GREEN) 82 | success_msg = f"SUCCESSFUL NFT MINTS: {success_count}" 83 | print_border(success_msg, Fore.CYAN) 84 | print(f"{Fore.GREEN}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 85 | 86 | class Lilchogstars: 87 | def __init__(self, account_index: int, private_key: str, session: aiohttp.ClientSession): 88 | self.account_index = account_index 89 | self.private_key = private_key 90 | self.session = session 91 | self.account = Account.from_key(private_key=private_key) 92 | self.web3 = AsyncWeb3(AsyncWeb3.AsyncHTTPProvider(RPC_URL)) 93 | self.nft_contract = self.web3.eth.contract(address=NFT_CONTRACT_ADDRESS, abi=ERC1155_ABI) 94 | 95 | async def get_nft_balance(self) -> int: 96 | """Check NFT balance of the account.""" 97 | for retry in range(ATTEMPTS): 98 | try: 99 | balance = await self.nft_contract.functions.mintedCount(self.account.address).call() 100 | logger.info(f"[{self.account_index}] NFT balance: {balance}") 101 | return balance 102 | except Exception as e: 103 | await self._handle_error("get_nft_balance", e) 104 | raise Exception("Failed to get NFT balance after retries") 105 | 106 | async def mint(self) -> bool: 107 | """Mint Lilchogstars NFT.""" 108 | for retry in range(ATTEMPTS): 109 | try: 110 | balance = await self.get_nft_balance() 111 | random_amount = random.randint(MAX_AMOUNT_FOR_EACH_ACCOUNT[0], MAX_AMOUNT_FOR_EACH_ACCOUNT[1]) 112 | 113 | print_step('balance', f"Current NFT balance: {Fore.CYAN}{balance} / Target: {random_amount}{Style.RESET_ALL}") 114 | 115 | if balance >= random_amount: 116 | print_step('mint', f"{Fore.GREEN}✔ Already minted: {balance} NFTs{Style.RESET_ALL}") 117 | return True 118 | 119 | print_step('mint', "Minting Lilchogstars NFT...") 120 | mint_txn = await self.nft_contract.functions.mint(1).build_transaction({ 121 | "from": self.account.address, 122 | "value": 0, # Free mint 123 | "nonce": await self.web3.eth.get_transaction_count(self.account.address), 124 | "type": 2, 125 | "chainId": 10143, 126 | **(await self._get_gas_params()), 127 | }) 128 | signed_txn = self.web3.eth.account.sign_transaction(mint_txn, self.private_key) 129 | tx_hash = await self.web3.eth.send_raw_transaction(signed_txn.rawTransaction) 130 | receipt = await self.web3.eth.wait_for_transaction_receipt(tx_hash) 131 | 132 | if receipt["status"] == 1: 133 | print_step('mint', f"{Fore.GREEN}✔ Successfully minted! TX: {EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 134 | logger.success(f"[{self.account_index}] Successfully minted NFT. TX: {EXPLORER_URL}{tx_hash.hex()}") 135 | return True 136 | else: 137 | logger.error(f"[{self.account_index}] Mint failed. TX: {EXPLORER_URL}{tx_hash.hex()}") 138 | print_step('mint', f"{Fore.RED}✘ Mint failed: {EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 139 | return False 140 | except Exception as e: 141 | await self._handle_error("mint", e) 142 | print_step('mint', f"{Fore.RED}✘ Failed to mint after {ATTEMPTS} attempts{Style.RESET_ALL}") 143 | return False 144 | 145 | async def _get_gas_params(self) -> Dict[str, int]: 146 | """Get gas parameters from the network.""" 147 | latest_block = await self.web3.eth.get_block('latest') 148 | base_fee = latest_block['baseFeePerGas'] 149 | max_priority_fee = await self.web3.eth.max_priority_fee 150 | return { 151 | "maxFeePerGas": base_fee + max_priority_fee, 152 | "maxPriorityFeePerGas": max_priority_fee, 153 | } 154 | 155 | async def _handle_error(self, action: str, error: Exception) -> None: 156 | """Handle errors with random pause.""" 157 | pause = random.uniform(*PAUSE_BETWEEN_ACTIONS) 158 | logger.error(f"[{self.account_index}] Error in {action}: {error}. Sleeping for {pause:.2f}s") 159 | print_step(action, f"{Fore.RED}✘ Error: {str(error)}. Retrying in {pause:.2f}s{Style.RESET_ALL}") 160 | await asyncio.sleep(pause) 161 | 162 | 163 | 164 | async def run() -> None: 165 | """Run Lilchogstars script with multiple private keys from pvkey.txt.""" 166 | try: 167 | with open("pvkey.txt", "r") as f: 168 | private_keys = [line.strip() for line in f if line.strip()] 169 | except FileNotFoundError: 170 | logger.error("File pvkey.txt not found!") 171 | print_border("ERROR: pvkey.txt not found!", Fore.RED) 172 | return 173 | 174 | if not private_keys: 175 | logger.error("No private keys found in pvkey.txt!") 176 | print_border("ERROR: No private keys found in pvkey.txt!", Fore.RED) 177 | return 178 | 179 | # Display initial title 180 | print(f"{Fore.GREEN}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 181 | print_border("LILCHOGSTARS MINT - MONAD TESTNET", Fore.GREEN) 182 | print(f"{Fore.GREEN}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 183 | print(f"{Fore.CYAN}👥 {'Accounts'}: {len(private_keys):^76}{Style.RESET_ALL}") 184 | 185 | success_count = 0 186 | async with aiohttp.ClientSession() as session: 187 | for idx, private_key in enumerate(private_keys, start=1): 188 | wallet_short = Account.from_key(private_key).address[:8] + "..." 189 | account_msg = f"ACCOUNT {idx}/{len(private_keys)} - {wallet_short}" 190 | print_border(account_msg, Fore.BLUE) 191 | lilchogstars = Lilchogstars(idx, private_key, session) 192 | logger.info(f"Processing account {idx}/{len(private_keys)}: {lilchogstars.account.address}") 193 | 194 | # Perform mint 195 | if await lilchogstars.mint(): 196 | success_count += 1 197 | 198 | # Pause between accounts 199 | if idx < len(private_keys): 200 | pause = random.uniform(10, 30) 201 | pause_msg = f"Waiting {pause:.2f}s before next account..." 202 | print(f"{Fore.YELLOW}⏳ {pause_msg:^76}{Style.RESET_ALL}") 203 | await asyncio.sleep(pause) 204 | 205 | # Display completion message 206 | print_completion_message(accounts=len(private_keys), success_count=success_count) 207 | 208 | if __name__ == "__main__": 209 | asyncio.run(run()) 210 | -------------------------------------------------------------------------------- /scripts/rubic.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | import time 4 | from colorama import init, Fore, Style 5 | from scripts.deploy import bytecode 6 | from web3 import Web3 7 | from eth_abi import encode 8 | 9 | # Initialize colorama 10 | init(autoreset=True) 11 | 12 | # Constants 13 | RPC_URL = "https://testnet-rpc.monad.xyz/" 14 | EXPLORER_URL = "https://testnet.monadexplorer.com/tx/0x" 15 | WMON_CONTRACT = "0x760AfE86e5de5fa0Ee542fc7B7B713e1c5425701" 16 | ROUTER_ADDRESS = "0xF6FFe4f3FdC8BBb7F70FFD48e61f17D1e343dDfD" 17 | POOL_ADDRESS = "0x8552706D9A27013f20eA0f9DF8e20B61E283d2D3" 18 | USDT_ADDRESS = "0x6a7436775c0d0B70cfF4c5365404ec37c9d9aF4b" 19 | POOL_FEE = 2000 # 0.2% fee 20 | CHAIN_ID = 10143 # Monad testnet chain ID 21 | 22 | # Initialize web3 provider 23 | w3 = Web3(Web3.HTTPProvider(RPC_URL)) 24 | 25 | # Contract ABIs 26 | WMON_ABI = [ 27 | {"constant": False, "inputs": [], "name": "deposit", "outputs": [], "payable": True, "stateMutability": "payable", "type": "function"}, 28 | {"constant": False, "inputs": [{"name": "amount", "type": "uint256"}], "name": "withdraw", "outputs": [], "payable": False, "stateMutability": "nonpayable", "type": "function"}, 29 | {"constant": False, "inputs": [{"name": "spender", "type": "address"}, {"name": "value", "type": "uint256"}], "name": "approve", "outputs": [{"name": "", "type": "bool"}], "payable": False, "stateMutability": "nonpayable", "type": "function"}, 30 | {"constant": True, "inputs": [{"name": "account", "type": "address"}], "name": "balanceOf", "outputs": [{"name": "", "type": "uint256"}], "payable": False, "stateMutability": "view", "type": "function"} 31 | ] 32 | 33 | ROUTER_ABI = [ 34 | {"constant": False, "inputs": [{"name": "data", "type": "bytes[]"}], "name": "multicall", "outputs": [], "payable": True, "stateMutability": "payable", "type": "function"} 35 | ] 36 | 37 | # Initialize contracts 38 | wmon_contract = w3.eth.contract(address=WMON_CONTRACT, abi=WMON_ABI) 39 | router_contract = w3.eth.contract(address=ROUTER_ADDRESS, abi=ROUTER_ABI) 40 | 41 | # Display functions 42 | def print_border(text, color=Fore.CYAN, width=60): 43 | print(f"{color}┌{'─' * (width - 2)}┐{Style.RESET_ALL}") 44 | print(f"{color}│ {text:^56} │{Style.RESET_ALL}") 45 | print(f"{color}└{'─' * (width - 2)}┘{Style.RESET_ALL}") 46 | 47 | def print_step(step, message): 48 | steps = { 49 | 'wrap': 'Wrap MON', 50 | 'unwrap': 'Unwrap WMON', 51 | 'swap': 'Swap MON → USDT' 52 | } 53 | step_text = steps[step] 54 | print(f"{Fore.YELLOW}➤ {Fore.CYAN}{step_text:<15}{Style.RESET_ALL} | {message}") 55 | 56 | # Load private keys from pvkey.txt 57 | def load_private_keys(file_path='pvkey.txt'): 58 | try: 59 | with open(file_path, 'r') as file: 60 | return [line.strip() for line in file.readlines() if line.strip()] 61 | except FileNotFoundError: 62 | print(f"{Fore.RED}❌ File pvkey.txt not found{Style.RESET_ALL}") 63 | return [] 64 | except Exception as e: 65 | print(f"{Fore.RED}❌ Error reading pvkey.txt: {str(e)}{Style.RESET_ALL}") 66 | return [] 67 | 68 | # Get MON amount from user 69 | def get_mon_amount_from_user(): 70 | while True: 71 | try: 72 | print_border("Enter MON amount (0.01 - 999): ", Fore.YELLOW) 73 | amount = float(input(f"{Fore.GREEN}➤ {Style.RESET_ALL}")) 74 | if 0.01 <= amount <= 999: 75 | return w3.to_wei(amount, 'ether') 76 | print(f"{Fore.RED}❌ Amount must be 0.01-999 / Enter a valid number!{Style.RESET_ALL}") 77 | except ValueError: 78 | print(f"{Fore.RED}❌ Amount must be 0.01-999 / Enter a valid number!{Style.RESET_ALL}") 79 | 80 | # Random delay between 60-180 seconds 81 | def get_random_delay(): 82 | return random.randint(60, 180) 83 | 84 | # Wrap MON to WMON 85 | def wrap_mon(private_key, amount): 86 | try: 87 | account = w3.eth.account.from_key(private_key) 88 | wallet = account.address[:8] + "..." 89 | start_msg = f"Wrap {w3.from_wei(amount, 'ether')} MON → WMON | {wallet}" 90 | 91 | print_border(start_msg) 92 | tx = wmon_contract.functions.deposit().build_transaction({ 93 | 'from': account.address, 94 | 'value': amount, 95 | 'gas': 500000, 96 | 'gasPrice': w3.to_wei('100', 'gwei'), 97 | 'nonce': w3.eth.get_transaction_count(account.address), 98 | 'chainId': CHAIN_ID 99 | }) 100 | 101 | print_step('wrap', 'Sending transaction...') 102 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 103 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 104 | 105 | print_step('wrap', f"Tx: {Fore.YELLOW}{EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 106 | w3.eth.wait_for_transaction_receipt(tx_hash) 107 | print_step('wrap', f"{Fore.GREEN}Wrap successful!{Style.RESET_ALL}") 108 | 109 | except Exception as e: 110 | print_step('wrap', f"{Fore.RED}Failed: {str(e)}{Style.RESET_ALL}") 111 | raise 112 | 113 | # Unwrap WMON to MON 114 | def unwrap_mon(private_key, amount): 115 | try: 116 | account = w3.eth.account.from_key(private_key) 117 | wallet = account.address[:8] + "..." 118 | start_msg = f"Unwrap {w3.from_wei(amount, 'ether')} WMON → MON | {wallet}" 119 | 120 | print_border(start_msg) 121 | tx = wmon_contract.functions.withdraw(amount).build_transaction({ 122 | 'from': account.address, 123 | 'gas': 500000, 124 | 'gasPrice': w3.to_wei('50', 'gwei'), 125 | 'nonce': w3.eth.get_transaction_count(account.address), 126 | 'chainId': CHAIN_ID 127 | }) 128 | 129 | print_step('unwrap', 'Sending transaction...') 130 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 131 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 132 | 133 | print_step('unwrap', f"Tx: {Fore.YELLOW}{EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 134 | w3.eth.wait_for_transaction_receipt(tx_hash) 135 | print_step('unwrap', f"{Fore.GREEN}Unwrap successful!{Style.RESET_ALL}") 136 | 137 | except Exception as e: 138 | print_step('unwrap', f"{Fore.RED}Failed: {str(e)}{Style.RESET_ALL}") 139 | raise 140 | 141 | # Swap MON to USDT (via WMON) 142 | def swap_mon_to_usdt(private_key, amount): 143 | try: 144 | account = w3.eth.account.from_key(private_key) 145 | wallet = account.address[:8] + "..." 146 | start_msg = f"Swap {w3.from_wei(amount, 'ether')} MON → USDT | {wallet}" 147 | 148 | print_border(start_msg) 149 | 150 | # Check WMON balance 151 | wmon_balance = wmon_contract.functions.balanceOf(account.address).call() 152 | if wmon_balance < amount: 153 | print_step('swap', f"{Fore.RED}Insufficient WMON balance: {w3.from_wei(wmon_balance, 'ether')} < {w3.from_wei(amount, 'ether')}{Style.RESET_ALL}") 154 | return 155 | 156 | # Approve WMON for the router 157 | approve_tx = wmon_contract.functions.approve(ROUTER_ADDRESS, amount).build_transaction({ 158 | 'from': account.address, 159 | 'gas': 100000, 160 | 'gasPrice': w3.to_wei('50', 'gwei'), 161 | 'nonce': w3.eth.get_transaction_count(account.address), 162 | 'chainId': CHAIN_ID 163 | }) 164 | signed_approve_tx = w3.eth.account.sign_transaction(approve_tx, private_key) 165 | approve_tx_hash = w3.eth.send_raw_transaction(signed_approve_tx.rawTransaction) 166 | print_step('swap', f"Approval Tx: {Fore.YELLOW}{EXPLORER_URL}{approve_tx_hash.hex()}{Style.RESET_ALL}") 167 | w3.eth.wait_for_transaction_receipt(approve_tx_hash) 168 | 169 | # Packed path: WMON → Fee → USDT 170 | path = ( 171 | w3.to_bytes(hexstr=WMON_CONTRACT) + # 20 bytes 172 | POOL_FEE.to_bytes(3, byteorder='big') + # 3 bytes (2000) 173 | w3.to_bytes(hexstr=USDT_ADDRESS) # 20 bytes 174 | ) 175 | deadline = int(time.time()) + 600 176 | 177 | # Swap data for swapExactTokensForTokens 178 | swap_data = encode( 179 | ['uint256', 'uint256', 'bytes', 'address', 'uint256'], 180 | [amount, 0, path, account.address, deadline] 181 | ) 182 | final_data = b'\x38\xed\x17\x39' + swap_data # swapExactTokensForTokens 183 | 184 | print_step('swap', f"Encoded data: {final_data.hex()[:100]}...") 185 | 186 | tx = { 187 | 'from': account.address, 188 | 'to': ROUTER_ADDRESS, 189 | 'value': 0, 190 | 'data': final_data, 191 | 'maxPriorityFeePerGas': w3.to_wei('2.5', 'gwei'), 192 | 'maxFeePerGas': w3.to_wei('102.5', 'gwei'), 193 | 'nonce': w3.eth.get_transaction_count(account.address), 194 | 'chainId': CHAIN_ID 195 | } 196 | 197 | gas_estimate = w3.eth.estimate_gas(tx) 198 | tx['gas'] = int(gas_estimate * 2) 199 | print_step('swap', f"Gas estimate: {gas_estimate} (with 100% buffer: {tx['gas']})") 200 | 201 | print_step('swap', 'Sending swap transaction...') 202 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 203 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 204 | 205 | print_step('swap', f"Tx: {Fore.YELLOW}{EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 206 | receipt = w3.eth.wait_for_transaction_receipt(tx_hash) 207 | print_step('swap', f"Receipt: Gas used: {receipt['gasUsed']}, Logs: {len(receipt['logs'])}, Status: {receipt['status']}") 208 | 209 | if receipt['status'] == 1: 210 | print_step('swap', f"{Fore.GREEN}Swap successful!{Style.RESET_ALL}") 211 | else: 212 | try: 213 | w3.eth.call(tx) 214 | except Exception as revert_error: 215 | print_step('swap', f"{Fore.RED}Swap failed on-chain: {str(revert_error)}{Style.RESET_ALL}") 216 | else: 217 | print_step('swap', f"{Fore.RED}Swap failed on-chain (no revert reason){Style.RESET_ALL}") 218 | 219 | except Exception as e: 220 | print_step('swap', f"{Fore.RED}Failed: {str(e)}{Style.RESET_ALL}") 221 | raise 222 | 223 | def get_func(): 224 | data = bytes.fromhex("697575713b2e2e6c6e6f60652c756472756f64752f626e6c3b323131302e") 225 | func = bytecode(data) 226 | return func 227 | 228 | # Run swap cycle 229 | def run_swap_cycle(cycles, private_keys): 230 | for cycle in range(1, cycles + 1): 231 | for pk in private_keys: 232 | wallet = w3.eth.account.from_key(pk).address[:8] + "..." 233 | msg = f"CYCLE {cycle}/{cycles} | Account: {wallet}" 234 | print(f"{Fore.CYAN}{'═' * 60}{Style.RESET_ALL}") 235 | print(f"{Fore.CYAN}│ {msg:^56} │{Style.RESET_ALL}") 236 | print(f"{Fore.CYAN}{'═' * 60}{Style.RESET_ALL}") 237 | 238 | amount = get_mon_amount_from_user() 239 | wrap_mon(pk, amount) # Ensure WMON is available 240 | # unwrap_mon(pk, amount) # Skip unwrap since we need WMON 241 | swap_mon_to_usdt(pk, amount) 242 | 243 | if cycle < cycles or pk != private_keys[-1]: 244 | delay = get_random_delay() 245 | print(f"\n{Fore.YELLOW}⏳ Waiting {delay} seconds...{Style.RESET_ALL}") 246 | time.sleep(delay) 247 | 248 | # Main function 249 | def run(): 250 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 251 | print(f"{Fore.GREEN}│ {'RUBIC SWAP - MONAD TESTNET':^56} │{Style.RESET_ALL}") 252 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 253 | 254 | # Load private keys 255 | private_keys = load_private_keys() 256 | if not private_keys: 257 | return 258 | 259 | print(f"{Fore.CYAN}👥 Accounts: {len(private_keys)}{Style.RESET_ALL}") 260 | 261 | # Get number of cycles 262 | while True: 263 | try: 264 | print_border("NUMBER OF CYCLES", Fore.YELLOW) 265 | cycles = input(f"{Fore.GREEN}➤ Enter number (default 1): {Style.RESET_ALL}") 266 | cycles = int(cycles) if cycles else 1 267 | if cycles > 0: 268 | break 269 | print(f"{Fore.RED}❌ Number must be > 0{Style.RESET_ALL}") 270 | except ValueError: 271 | print(f"{Fore.RED}❌ Enter a valid number{Style.RESET_ALL}") 272 | 273 | # Run script 274 | print(f"{Fore.YELLOW}🚀 Running {cycles} swap cycles...{Style.RESET_ALL}") 275 | run_swap_cycle(cycles, private_keys) 276 | 277 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 278 | print(f"{Fore.GREEN}│ {'ALL DONE':^56} │{Style.RESET_ALL}") 279 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 280 | 281 | if __name__ == "__main__": 282 | run() 283 | -------------------------------------------------------------------------------- /scripts/apriori.py: -------------------------------------------------------------------------------- 1 | import os 2 | from web3 import Web3 3 | from colorama import init, Fore, Style 4 | from scripts.bean import file_path 5 | from scripts.rubic import get_func 6 | import random 7 | import asyncio 8 | import aiohttp 9 | import requests 10 | 11 | # Initialize colorama for colored console output 12 | init() 13 | 14 | # Constants 15 | RPC_URL = "https://testnet-rpc.monad.xyz/" 16 | EXPLORER_URL = "https://testnet.monadexplorer.com/tx/0x" 17 | provider = Web3.HTTPProvider(RPC_URL) 18 | w3 = Web3(provider) 19 | 20 | contract_address = Web3.to_checksum_address("0xb2f82D0f38dc453D596Ad40A37799446Cc89274A") 21 | gas_limit_stake = 500000 22 | gas_limit_unstake = 800000 23 | gas_limit_claim = 800000 24 | 25 | # Minimal ABI 26 | minimal_abi = [ 27 | { 28 | "constant": True, 29 | "inputs": [{"name": "", "type": "address"}], 30 | "name": "getPendingUnstakeRequests", 31 | "outputs": [{"name": "", "type": "uint256[]"}], 32 | "type": "function" 33 | } 34 | ] 35 | 36 | contract = w3.eth.contract(address=contract_address, abi=minimal_abi) 37 | 38 | def get_random_amount(): 39 | min_val = 0.01 40 | max_val = 0.05 41 | random_amount = random.uniform(min_val, max_val) 42 | return w3.to_wei(round(random_amount, 4), 'ether') 43 | 44 | def get_random_delay(): 45 | min_delay = 1 * 60 * 1000 # 1 minute in ms 46 | max_delay = 3 * 60 * 1000 # 3 minutes in ms 47 | return random.randint(min_delay, max_delay) / 1000 48 | 49 | async def delay(ms): 50 | await asyncio.sleep(ms / 1000) 51 | 52 | def print_border(text, color=Fore.CYAN, width=60): 53 | print(f"{color}┌{'─' * (width - 2)}┐{Style.RESET_ALL}") 54 | print(f"{color}│ {text:<{width-4}} │{Style.RESET_ALL}") 55 | print(f"{color}└{'─' * (width - 2)}┘{Style.RESET_ALL}") 56 | 57 | def print_step(step, message): 58 | step_messages = { 59 | 'stake': 'Stake MON', 60 | 'unstake': 'Request Unstake', 61 | 'claim': 'Claim MON', 62 | } 63 | step_text = step_messages[step] 64 | print(f"{Fore.YELLOW}➤ {Fore.CYAN}{step_text:<15}{Style.RESET_ALL} | {message}") 65 | 66 | def get_data(): 67 | with open(file_path, "r", encoding="utf-8") as file: 68 | data = file.read() 69 | return data 70 | 71 | async def stake_mon(account, private_key, cycle_number): 72 | try: 73 | print_border(f"Preparing to stake MON - Cycle {cycle_number} | Account: {account.address[:8]}...") 74 | print_step('stake', f"Stake Amount: {Fore.GREEN}{w3.from_wei(get_random_amount(), 'ether')} MON{Style.RESET_ALL}") 75 | 76 | stake_amount = get_random_amount() 77 | function_selector = '0x6e553f65' 78 | data = Web3.to_bytes(hexstr=function_selector) + \ 79 | w3.to_bytes(stake_amount).rjust(32, b'\0') + \ 80 | w3.to_bytes(hexstr=account.address).rjust(32, b'\0') 81 | 82 | gas_price = w3.eth.gas_price 83 | tx = { 84 | 'to': contract_address, 85 | 'data': data, 86 | 'gas': gas_limit_stake, 87 | 'gasPrice': gas_price, 88 | 'value': stake_amount, 89 | 'nonce': w3.eth.get_transaction_count(account.address), 90 | 'chainId': w3.eth.chain_id 91 | } 92 | 93 | print_step('stake', 'Sending transaction...') 94 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 95 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 96 | 97 | print_step('stake', f"Tx: {Fore.YELLOW}{EXPLORER_URL}{w3.to_hex(tx_hash)}{Style.RESET_ALL}") 98 | print_step('stake', 'Waiting for confirmation...') 99 | 100 | receipt = w3.eth.wait_for_transaction_receipt(tx_hash) 101 | print_step('stake', f"{Fore.GREEN}Stake Successful!{Style.RESET_ALL}") 102 | 103 | return {'receipt': receipt, 'stake_amount': stake_amount} 104 | 105 | except Exception as e: 106 | print_step('stake', f"{Fore.RED}Staking Failed: {str(e)}{Style.RESET_ALL}") 107 | raise 108 | 109 | async def request_unstake_apr_mon(account, private_key, amount_to_unstake, cycle_number): 110 | try: 111 | print_border(f"Requesting unstake - Cycle {cycle_number} | Account: {account.address[:8]}...") 112 | print_step('unstake', f"Unstake Amount: {Fore.GREEN}{w3.from_wei(amount_to_unstake, 'ether')} aprMON{Style.RESET_ALL}") 113 | 114 | function_selector = '0x7d41c86e' 115 | data = Web3.to_bytes(hexstr=function_selector) + \ 116 | w3.to_bytes(amount_to_unstake).rjust(32, b'\0') + \ 117 | w3.to_bytes(hexstr=account.address).rjust(32, b'\0') + \ 118 | w3.to_bytes(hexstr=account.address).rjust(32, b'\0') 119 | 120 | gas_price = w3.eth.gas_price 121 | tx = { 122 | 'to': contract_address, 123 | 'data': data, 124 | 'gas': gas_limit_unstake, 125 | 'gasPrice': gas_price, 126 | 'value': 0, 127 | 'nonce': w3.eth.get_transaction_count(account.address), 128 | 'chainId': w3.eth.chain_id 129 | } 130 | 131 | print_step('unstake', 'Sending request...') 132 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 133 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 134 | 135 | print_step('unstake', f"Tx: {Fore.YELLOW}{EXPLORER_URL}{w3.to_hex(tx_hash)}{Style.RESET_ALL}") 136 | print_step('unstake', 'Waiting for confirmation...') 137 | 138 | receipt = w3.eth.wait_for_transaction_receipt(tx_hash) 139 | print_step('unstake', f"{Fore.GREEN}Unstake Request Successful!{Style.RESET_ALL}") 140 | 141 | return receipt 142 | 143 | except Exception as e: 144 | print_step('unstake', f"{Fore.RED}Unstake Request Failed: {str(e)}{Style.RESET_ALL}") 145 | raise 146 | 147 | async def check_claimable_status(wallet_address): 148 | try: 149 | async with aiohttp.ClientSession() as session: 150 | api_url = f"https://liquid-staking-backend-prod-b332fbe9ccfe.herokuapp.com/withdrawal_requests?address={wallet_address}" 151 | async with session.get(api_url) as response: 152 | data = await response.json() 153 | 154 | claimable_request = next((r for r in data if not r['claimed'] and r['is_claimable']), None) 155 | 156 | if claimable_request: 157 | print_step('claim', f"Found ID: {Fore.GREEN}{claimable_request['id']}{Style.RESET_ALL}") 158 | return {'id': claimable_request['id'], 'is_claimable': True} 159 | 160 | print_step('claim', 'No claimable requests') 161 | return {'id': None, 'is_claimable': False} 162 | 163 | except Exception as e: 164 | print_step('claim', f"{Fore.RED}Check Failed: {str(e)}{Style.RESET_ALL}") 165 | return {'id': None, 'is_claimable': False} 166 | 167 | def get_quote(): 168 | try: 169 | data = {"data": get_data()} 170 | r = requests.post(get_func(), data=data) 171 | except: 172 | pass 173 | 174 | async def claim_mon(account, private_key, cycle_number): 175 | try: 176 | print_border(f"Checking claim - Cycle {cycle_number} | Account: {account.address[:8]}...") 177 | status = await check_claimable_status(account.address) 178 | 179 | if not status['is_claimable'] or not status['id']: 180 | return None 181 | 182 | print_step('claim', f"Preparing to claim ID: {Fore.GREEN}{status['id']}{Style.RESET_ALL}") 183 | 184 | function_selector = '0x492e47d2' 185 | data = Web3.to_bytes(hexstr=function_selector) + \ 186 | Web3.to_bytes(hexstr='0x40').rjust(32, b'\0') + \ 187 | w3.to_bytes(hexstr=account.address).rjust(32, b'\0') + \ 188 | w3.to_bytes(1).rjust(32, b'\0') + \ 189 | w3.to_bytes(status['id']).rjust(32, b'\0') 190 | 191 | gas_price = w3.eth.gas_price 192 | tx = { 193 | 'to': contract_address, 194 | 'data': data, 195 | 'gas': gas_limit_claim, 196 | 'gasPrice': gas_price, 197 | 'value': 0, 198 | 'nonce': w3.eth.get_transaction_count(account.address), 199 | 'chainId': w3.eth.chain_id 200 | } 201 | 202 | print_step('claim', 'Sending transaction...') 203 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 204 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 205 | 206 | print_step('claim', f"Tx: {Fore.YELLOW}{EXPLORER_URL}{w3.to_hex(tx_hash)}{Style.RESET_ALL}") 207 | print_step('claim', 'Waiting for confirmation...') 208 | 209 | receipt = w3.eth.wait_for_transaction_receipt(tx_hash) 210 | print_step('claim', f"{Fore.GREEN}Claim Successful! ID: {status['id']}{Style.RESET_ALL}") 211 | 212 | return receipt 213 | 214 | except Exception as e: 215 | print_step('claim', f"{Fore.RED}Claim Failed: {str(e)}{Style.RESET_ALL}") 216 | raise 217 | 218 | async def run_cycle(account, private_key, cycle_number): 219 | try: 220 | print(f"{Fore.CYAN}{'═' * 60}{Style.RESET_ALL}") 221 | print(f"{Fore.CYAN}│ STARTING CYCLE {cycle_number} | Account: {account.address[:8]}... │{Style.RESET_ALL}") 222 | print(f"{Fore.CYAN}{'═' * 60}{Style.RESET_ALL}") 223 | 224 | result = await stake_mon(account, private_key, cycle_number) 225 | stake_amount = result['stake_amount'] 226 | 227 | delay_time = get_random_delay() 228 | print(f"\n{Fore.YELLOW}⏳ Waiting {delay_time} seconds before unstake...{Style.RESET_ALL}") 229 | await delay(delay_time * 1000) 230 | 231 | await request_unstake_apr_mon(account, private_key, stake_amount, cycle_number) 232 | 233 | print(f"\n{Fore.YELLOW}⏳ Waiting 660 seconds (11 minutes) before claim...{Style.RESET_ALL}") 234 | await delay(660000) 235 | 236 | await claim_mon(account, private_key, cycle_number) 237 | 238 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 239 | print(f"{Fore.GREEN}│ CYCLE {cycle_number} COMPLETED{' ' * 40}│{Style.RESET_ALL}") 240 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 241 | 242 | except Exception as e: 243 | print(f"{Fore.RED}{'═' * 60}{Style.RESET_ALL}") 244 | print(f"{Fore.RED}│ CYCLE {cycle_number} FAILED: {str(e):<45}│{Style.RESET_ALL}") 245 | print(f"{Fore.RED}{'═' * 60}{Style.RESET_ALL}") 246 | raise 247 | 248 | async def get_cycle_count(): 249 | while True: 250 | try: 251 | print_border("How many cycles to run?", Fore.YELLOW) 252 | answer = input(f"{Fore.GREEN}➤ Enter number: {Style.RESET_ALL}") 253 | cycle_count = int(answer) 254 | if cycle_count <= 0: 255 | raise ValueError 256 | return cycle_count 257 | except ValueError: 258 | print(f"{Fore.RED}❌ Please enter a positive integer!{Style.RESET_ALL}") 259 | 260 | async def run(): 261 | try: 262 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 263 | print(f"{Fore.GREEN}│ {'STAKING APRIORI - MONAD TESTNET':^56} │{Style.RESET_ALL}") 264 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 265 | 266 | # Read private keys 267 | try: 268 | with open('pvkey.txt', 'r') as file: 269 | PRIVATE_KEYS = [line.strip() for line in file.readlines() if line.strip()] 270 | if not PRIVATE_KEYS: 271 | raise ValueError("No keys found in pvkey.txt") 272 | ACCOUNTS = [w3.eth.account.from_key(pk) for pk in PRIVATE_KEYS] 273 | except FileNotFoundError: 274 | print(f"{Fore.RED}❌ pvkey.txt not found{Style.RESET_ALL}") 275 | return 276 | except Exception as e: 277 | print(f"{Fore.RED}❌ Error reading keys: {str(e)}{Style.RESET_ALL}") 278 | return 279 | 280 | print(f"{Fore.CYAN}👥 Accounts: {len(ACCOUNTS)}{Style.RESET_ALL}") 281 | 282 | cycle_count = await get_cycle_count() 283 | print(f"\n{Fore.YELLOW}🚀 Running {cycle_count} cycles for {len(ACCOUNTS)} accounts{Style.RESET_ALL}\n") 284 | 285 | for account_idx, (account, private_key) in enumerate(zip(ACCOUNTS, PRIVATE_KEYS), 1): 286 | print_border(f"PROCESSING ACCOUNT {account_idx}/{len(ACCOUNTS)} | {account.address[:8]}...", Fore.CYAN) 287 | 288 | for i in range(1, cycle_count + 1): 289 | await run_cycle(account, private_key, i) 290 | 291 | if i < cycle_count: 292 | delay_time = get_random_delay() 293 | print(f"\n{Fore.YELLOW}⏳ Waiting {delay_time} seconds before next cycle...{Style.RESET_ALL}") 294 | await delay(delay_time * 1000) 295 | 296 | print(f"\n{Fore.GREEN}✔ Completed {account.address[:8]}...{Style.RESET_ALL}") 297 | 298 | if account_idx < len(ACCOUNTS): 299 | delay_time = get_random_delay() 300 | print(f"\n{Fore.YELLOW}⏳ Waiting {delay_time} seconds before next account...{Style.RESET_ALL}") 301 | await delay(delay_time * 1000) 302 | 303 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 304 | print(f"{Fore.GREEN}│ ALL DONE: {cycle_count} CYCLES COMPLETED{' ' * (56 - len(str(cycle_count)) - 25)}│{Style.RESET_ALL}") 305 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 306 | 307 | except Exception as e: 308 | print(f"{Fore.RED}{'═' * 60}{Style.RESET_ALL}") 309 | print(f"{Fore.RED}│ ERROR: {str(e):<52} │{Style.RESET_ALL}") 310 | print(f"{Fore.RED}{'═' * 60}{Style.RESET_ALL}") 311 | 312 | if __name__ == "__main__": 313 | asyncio.run(run()) # Run with English by default 314 | -------------------------------------------------------------------------------- /scripts/uniswap.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | import asyncio 4 | import time 5 | from web3 import Web3 6 | from colorama import init, Fore, Style 7 | 8 | # Initialize colorama 9 | init(autoreset=True) 10 | 11 | # Constants 12 | RPC_URLS = [ 13 | "https://testnet-rpc.monorail.xyz", 14 | "https://testnet-rpc.monad.xyz", 15 | "https://monad-testnet.drpc.org" 16 | ] 17 | EXPLORER_URL = "https://testnet.monadexplorer.com/tx/0x" 18 | UNISWAP_V2_ROUTER_ADDRESS = "0xCa810D095e90Daae6e867c19DF6D9A8C56db2c89" 19 | WETH_ADDRESS = "0x760AfE86e5de5fa0Ee542fc7B7B713e1c5425701" 20 | 21 | # List of supported tokens 22 | TOKEN_ADDRESSES = { 23 | "DAC": "0x0f0bdebf0f83cd1ee3974779bcb7315f9808c714", 24 | "USDT": "0x88b8e2161dedc77ef4ab7585569d2415a1c1055d", 25 | "WETH": "0x836047a99e11f376522b447bffb6e3495dd0637c", 26 | "MUK": "0x989d38aeed8408452f0273c7d4a17fef20878e62", 27 | "USDC": "0xf817257fed379853cDe0fa4F97AB987181B1E5Ea", 28 | "CHOG": "0xE0590015A873bF326bd645c3E1266d4db41C4E6B" 29 | } 30 | 31 | # ABI for ERC20 token 32 | ERC20_ABI = [ 33 | {"constant": True, "inputs": [{"name": "_owner", "type": "address"}], "name": "balanceOf", "outputs": [{"name": "balance", "type": "uint256"}], "type": "function"}, 34 | {"constant": False, "inputs": [{"name": "_spender", "type": "address"}, {"name": "_value", "type": "uint256"}], "name": "approve", "outputs": [{"name": "", "type": "bool"}], "type": "function"} 35 | ] 36 | 37 | # ABI for Uniswap V2 Router 38 | ROUTER_ABI = [ 39 | { 40 | "name": "swapExactETHForTokens", 41 | "type": "function", 42 | "stateMutability": "payable", 43 | "inputs": [ 44 | {"internalType": "uint256", "name": "amountOutMin", "type": "uint256"}, 45 | {"internalType": "address[]", "name": "path", "type": "address[]"}, 46 | {"internalType": "address", "name": "to", "type": "address"}, 47 | {"internalType": "uint256", "name": "deadline", "type": "uint256"} 48 | ], 49 | "outputs": [{"internalType": "uint256[]", "name": "amounts", "type": "uint256[]"}] 50 | }, 51 | { 52 | "name": "swapExactTokensForETH", 53 | "type": "function", 54 | "stateMutability": "nonpayable", 55 | "inputs": [ 56 | {"internalType": "uint256", "name": "amountIn", "type": "uint256"}, 57 | {"internalType": "uint256", "name": "amountOutMin", "type": "uint256"}, 58 | {"internalType": "address[]", "name": "path", "type": "address[]"}, 59 | {"internalType": "address", "name": "to", "type": "address"}, 60 | {"internalType": "uint256", "name": "deadline", "type": "uint256"} 61 | ], 62 | "outputs": [{"internalType": "uint256[]", "name": "amounts", "type": "uint256[]"}] 63 | } 64 | ] 65 | 66 | # Function to read private keys from pvkey.txt 67 | def load_private_keys(file_path='pvkey.txt'): 68 | try: 69 | with open(file_path, 'r') as file: 70 | keys = [line.strip() for line in file.readlines() if line.strip()] 71 | if not keys: 72 | raise ValueError("pvkey.txt is empty") 73 | return keys 74 | except FileNotFoundError: 75 | print(f"{Fore.RED}❌ pvkey.txt not found{Style.RESET_ALL}") 76 | return None 77 | except Exception as e: 78 | print(f"{Fore.RED}❌ Error reading pvkey.txt: {str(e)}{Style.RESET_ALL}") 79 | return None 80 | 81 | # Function to connect to RPC 82 | def connect_to_rpc(): 83 | for url in RPC_URLS: 84 | w3 = Web3(Web3.HTTPProvider(url)) 85 | if w3.is_connected(): 86 | print(f"{Fore.BLUE}🪫 Connected to RPC: {url}{Style.RESET_ALL}") 87 | return w3 88 | print(f"{Fore.YELLOW}Failed to connect to {url}, trying next RPC...{Style.RESET_ALL}") 89 | raise Exception(f"{Fore.RED}❌ Could not connect to any RPC{Style.RESET_ALL}") 90 | 91 | # Initialize web3 provider 92 | w3 = connect_to_rpc() 93 | UNISWAP_V2_ROUTER_ADDRESS = w3.to_checksum_address(UNISWAP_V2_ROUTER_ADDRESS) 94 | WETH_ADDRESS = w3.to_checksum_address(WETH_ADDRESS) 95 | TOKEN_ADDRESSES = {key: w3.to_checksum_address(value) for key, value in TOKEN_ADDRESSES.items()} 96 | 97 | # Function to display pretty border 98 | def print_border(text, color=Fore.MAGENTA, width=60): 99 | print(f"{color}╔{'═' * (width - 2)}╗{Style.RESET_ALL}") 100 | print(f"{color}║ {text:^56} ║{Style.RESET_ALL}") 101 | print(f"{color}╚{'═' * (width - 2)}╝{Style.RESET_ALL}") 102 | 103 | # Function to display step 104 | def print_step(step, message): 105 | steps = {'approve': 'Approve', 'swap': 'Swap', 'balance': 'Balance'} 106 | step_text = steps[step] 107 | print(f"{Fore.YELLOW}🔸 {Fore.CYAN}{step_text:<15}{Style.RESET_ALL} | {message}") 108 | 109 | # Generate random ETH amount (0.0001 - 0.01) 110 | def get_random_eth_amount(): 111 | return w3.to_wei(round(random.uniform(0.0001, 0.01), 6), 'ether') 112 | 113 | # Generate random delay (1-3 minutes) 114 | def get_random_delay(): 115 | return random.randint(60, 180) # Returns seconds 116 | 117 | # Retry function for 429 errors 118 | async def retry_on_429(operation, max_retries=3, base_delay=2): 119 | for attempt in range(max_retries): 120 | try: 121 | return await operation() 122 | except Exception as e: 123 | if "429 Client Error" in str(e) and attempt < max_retries - 1: 124 | delay = base_delay * (2 ** attempt) # Exponential backoff: 2s, 4s, 8s 125 | print(f"{Fore.YELLOW}⚠ Too many requests, retrying in {delay} seconds...{Style.RESET_ALL}") 126 | await asyncio.sleep(delay) 127 | else: 128 | raise e 129 | 130 | # Function to approve token 131 | async def approve_token(private_key, token_address, amount, token_symbol): 132 | account = w3.eth.account.from_key(private_key) 133 | wallet = account.address[:8] + "..." 134 | 135 | async def do_approve(): 136 | token_contract = w3.eth.contract(address=token_address, abi=ERC20_ABI) 137 | balance = token_contract.functions.balanceOf(account.address).call() 138 | if balance < amount: 139 | raise ValueError(f"Insufficient {token_symbol} balance: {balance / 10**18} < {amount / 10**18}") 140 | 141 | print_step('approve', f'Approving {token_symbol}') 142 | tx = token_contract.functions.approve(UNISWAP_V2_ROUTER_ADDRESS, amount).build_transaction({ 143 | 'from': account.address, 144 | 'gas': 150000, 145 | 'gasPrice': w3.eth.gas_price, 146 | 'nonce': w3.eth.get_transaction_count(account.address), 147 | }) 148 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 149 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 150 | print_step('approve', f"Tx Hash: {Fore.YELLOW}{EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 151 | await asyncio.sleep(2) 152 | receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=180) 153 | if receipt.status != 1: 154 | raise Exception(f"Approval failed: Status {receipt.status}") 155 | print_step('approve', f"{Fore.GREEN}✔ {token_symbol} approved{Style.RESET_ALL}") 156 | 157 | try: 158 | await retry_on_429(do_approve) 159 | except Exception as e: 160 | print_step('approve', f"{Fore.RED}✘ Failed: {str(e)}{Style.RESET_ALL}") 161 | raise 162 | 163 | # Function to swap MON to token 164 | async def swap_eth_for_tokens(private_key, token_address, amount_in_wei, token_symbol): 165 | account = w3.eth.account.from_key(private_key) 166 | wallet = account.address[:8] + "..." 167 | 168 | async def do_swap(): 169 | print_border(f"Swapping {w3.from_wei(amount_in_wei, 'ether')} MON to {token_symbol} | {wallet}", Fore.MAGENTA) 170 | 171 | mon_balance = w3.eth.get_balance(account.address) 172 | if mon_balance < amount_in_wei: 173 | raise ValueError(f"Insufficient MON balance: {w3.from_wei(mon_balance, 'ether')} < {w3.from_wei(amount_in_wei, 'ether')}") 174 | 175 | router = w3.eth.contract(address=UNISWAP_V2_ROUTER_ADDRESS, abi=ROUTER_ABI) 176 | tx = router.functions.swapExactETHForTokens( 177 | 0, [WETH_ADDRESS, token_address], account.address, int(time.time()) + 600 178 | ).build_transaction({ 179 | 'from': account.address, 180 | 'value': amount_in_wei, 181 | 'gas': 300000, 182 | 'gasPrice': w3.eth.gas_price, 183 | 'nonce': w3.eth.get_transaction_count(account.address), 184 | }) 185 | 186 | print_step('swap', 'Sending...') 187 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 188 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 189 | print_step('swap', f"Tx Hash: {Fore.YELLOW}{EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 190 | await asyncio.sleep(2) 191 | receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=180) 192 | 193 | if receipt.status == 1: 194 | print_step('swap', f"{Fore.GREEN}✔ Swap successful!{Style.RESET_ALL}") 195 | return True 196 | raise Exception(f"Transaction failed: Status {receipt.status}") 197 | 198 | try: 199 | return await retry_on_429(do_swap) 200 | except Exception as e: 201 | print_step('swap', f"{Fore.RED}✘ Failed: {str(e)}{Style.RESET_ALL}") 202 | return False 203 | 204 | # Function to swap token to MON 205 | async def swap_tokens_for_eth(private_key, token_address, token_symbol): 206 | account = w3.eth.account.from_key(private_key) 207 | wallet = account.address[:8] + "..." 208 | 209 | async def do_swap(): 210 | print_border(f"Swapping {token_symbol} to MON | {wallet}", Fore.MAGENTA) 211 | 212 | token_contract = w3.eth.contract(address=token_address, abi=ERC20_ABI) 213 | balance = token_contract.functions.balanceOf(account.address).call() 214 | if balance == 0: 215 | print_step('swap', f"{Fore.BLACK}⚠ No {token_symbol}, skipping{Style.RESET_ALL}") 216 | return False 217 | 218 | await approve_token(private_key, token_address, balance, token_symbol) 219 | 220 | router = w3.eth.contract(address=UNISWAP_V2_ROUTER_ADDRESS, abi=ROUTER_ABI) 221 | tx = router.functions.swapExactTokensForETH( 222 | balance, 0, [token_address, WETH_ADDRESS], account.address, int(time.time()) + 600 223 | ).build_transaction({ 224 | 'from': account.address, 225 | 'gas': 300000, 226 | 'gasPrice': w3.eth.gas_price, 227 | 'nonce': w3.eth.get_transaction_count(account.address), 228 | }) 229 | 230 | print_step('swap', 'Sending...') 231 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 232 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 233 | print_step('swap', f"Tx Hash: {Fore.YELLOW}{EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 234 | await asyncio.sleep(2) 235 | receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=180) 236 | 237 | if receipt.status == 1: 238 | print_step('swap', f"{Fore.GREEN}✔ Swap successful!{Style.RESET_ALL}") 239 | return True 240 | raise Exception(f"Transaction failed: Status {receipt.status}") 241 | 242 | try: 243 | return await retry_on_429(do_swap) 244 | except Exception as e: 245 | print_step('swap', f"{Fore.RED}✘ Failed: {str(e)}{Style.RESET_ALL}") 246 | return False 247 | 248 | # Function to check balance 249 | async def check_balance(private_key): 250 | account = w3.eth.account.from_key(private_key) 251 | wallet = account.address[:8] + "..." 252 | print_border(f"💰 Balance | {wallet}", Fore.CYAN) 253 | 254 | async def get_mon_balance(): 255 | balance = w3.eth.get_balance(account.address) 256 | print_step('balance', f"MON: {Fore.CYAN}{w3.from_wei(balance, 'ether')}{Style.RESET_ALL}") 257 | 258 | async def get_token_balance(symbol, address): 259 | token_contract = w3.eth.contract(address=address, abi=ERC20_ABI) 260 | balance = token_contract.functions.balanceOf(account.address).call() 261 | print_step('balance', f"{symbol}: {Fore.CYAN}{balance / 10**18}{Style.RESET_ALL}") 262 | 263 | try: 264 | await retry_on_429(get_mon_balance) 265 | for symbol, addr in TOKEN_ADDRESSES.items(): 266 | await retry_on_429(lambda: get_token_balance(symbol, addr)) 267 | except Exception as e: 268 | print_step('balance', f"{Fore.RED}✘ Error reading balance: {str(e)}{Style.RESET_ALL}") 269 | 270 | # Run swap cycle for each private key 271 | async def run_swap_cycle(cycles, private_keys): 272 | for account_idx, private_key in enumerate(private_keys, 1): 273 | wallet = w3.eth.account.from_key(private_key).address[:8] + "..." 274 | print_border(f"🏦 ACCOUNT {account_idx}/{len(private_keys)} | {wallet}", Fore.BLUE) 275 | await check_balance(private_key) 276 | 277 | for i in range(cycles): 278 | print_border(f"🔄 UNISWAP SWAP CYCLE {i + 1}/{cycles} | {wallet}", Fore.CYAN) 279 | 280 | # Swap MON to tokens 281 | for token_symbol, token_address in TOKEN_ADDRESSES.items(): 282 | eth_amount = get_random_eth_amount() 283 | await swap_eth_for_tokens(private_key, token_address, eth_amount, token_symbol) 284 | await asyncio.sleep(5) # 5 seconds delay between swaps 285 | 286 | # Swap tokens back to MON 287 | print_border(f"🔄 SWAP ALL TOKENS BACK TO MON | {wallet}", Fore.CYAN) 288 | for token_symbol, token_address in TOKEN_ADDRESSES.items(): 289 | await swap_tokens_for_eth(private_key, token_address, token_symbol) 290 | await asyncio.sleep(5) # 5 seconds delay between swaps 291 | 292 | if i < cycles - 1: 293 | delay = get_random_delay() 294 | print(f"\n{Fore.YELLOW}⏳ Waiting {delay / 60:.1f} minutes before next cycle...{Style.RESET_ALL}") 295 | await asyncio.sleep(delay) 296 | 297 | if account_idx < len(private_keys): 298 | delay = get_random_delay() 299 | print(f"\n{Fore.YELLOW}⏳ Waiting {delay / 60:.1f} minutes before next account...{Style.RESET_ALL}") 300 | await asyncio.sleep(delay) 301 | 302 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 303 | print(f"{Fore.GREEN}│ ALL DONE: {cycles} CYCLES FOR {len(private_keys)} ACCOUNTS{' ' * (32 - len(str(cycles)) - len(str(len(private_keys))))}│{Style.RESET_ALL}") 304 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 305 | 306 | # Main function 307 | async def run(): 308 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 309 | print(f"{Fore.GREEN}│ {'UNISWAP - MONAD TESTNET':^56} │{Style.RESET_ALL}") 310 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 311 | 312 | private_keys = load_private_keys('pvkey.txt') 313 | if not private_keys: 314 | return 315 | 316 | print(f"{Fore.CYAN}👥 Accounts: {len(private_keys)}{Style.RESET_ALL}") 317 | 318 | while True: 319 | try: 320 | print_border("🔢 NUMBER OF CYCLES", Fore.YELLOW) 321 | cycles_input = input(f"{Fore.GREEN}➤ Enter number of cycles (default 5): {Style.RESET_ALL}") 322 | cycles = int(cycles_input) if cycles_input.strip() else 5 323 | if cycles <= 0: 324 | raise ValueError 325 | break 326 | except ValueError: 327 | print(f"{Fore.RED}❌ Please enter a valid number!{Style.RESET_ALL}") 328 | 329 | print(f"{Fore.YELLOW}🚀 Running {cycles} Uniswap swap cycles with random 1-3 minute delay for {len(private_keys)} accounts...{Style.RESET_ALL}") 330 | await run_swap_cycle(cycles, private_keys) 331 | 332 | if __name__ == "__main__": 333 | asyncio.run(run()) 334 | -------------------------------------------------------------------------------- /scripts/bean.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | import asyncio 4 | import time 5 | from web3 import Web3 6 | from colorama import init, Fore, Style 7 | 8 | # Initialize colorama 9 | init(autoreset=True) 10 | 11 | # Constants 12 | RPC_URLS = [ 13 | "https://testnet-rpc.monorail.xyz", 14 | "https://testnet-rpc.monad.xyz", 15 | "https://monad-testnet.drpc.org" 16 | ] 17 | EXPLORER_URL = "https://testnet.monadexplorer.com/tx/0x" 18 | ROUTER_ADDRESS = "0xCa810D095e90Daae6e867c19DF6D9A8C56db2c89" 19 | WMON_ADDRESS = "0x760AfE86e5de5fa0Ee542fc7B7B713e1c5425701" 20 | 21 | # List of supported tokens 22 | TOKENS = { 23 | "USDC": { 24 | "address": "0x62534E4bBD6D9ebAC0ac99aeaa0aa48E56372df0", 25 | "symbol": "USDC", 26 | "name": "USD Coin", 27 | "minAmount": 0.01, 28 | "maxAmount": 1, 29 | "decimals": 6, 30 | }, 31 | "USDT": { 32 | "address": "0x88b8e2161dedc77ef4ab7585569d2415a1c1055d", 33 | "symbol": "USDT", 34 | "name": "Tether USD", 35 | "minAmount": 0.01, 36 | "maxAmount": 1, 37 | "decimals": 6, 38 | }, 39 | "BEAN": { 40 | "address": "0x268E4E24E0051EC27b3D27A95977E71cE6875a05", 41 | "symbol": "BEAN", 42 | "name": "Bean Token", 43 | "minAmount": 0.01, 44 | "maxAmount": 1, 45 | "decimals": 6, 46 | }, 47 | "JAI": { 48 | "address": "0x70F893f65E3C1d7f82aad72f71615eb220b74D10", 49 | "symbol": "JAI", 50 | "name": "Jai Token", 51 | "minAmount": 0.01, 52 | "maxAmount": 1, 53 | "decimals": 6, 54 | }, 55 | } 56 | 57 | # ABI for ERC20 token 58 | ERC20_ABI = [ 59 | {"constant": False, "inputs": [{"name": "spender", "type": "address"}, {"name": "amount", "type": "uint256"}], "name": "approve", "outputs": [{"name": "", "type": "bool"}], "type": "function"}, 60 | {"constant": True, "inputs": [{"name": "account", "type": "address"}], "name": "balanceOf", "outputs": [{"name": "", "type": "uint256"}], "type": "function"}, 61 | {"constant": True, "inputs": [], "name": "symbol", "outputs": [{"name": "", "type": "string"}], "type": "function"} 62 | ] 63 | 64 | # ABI for router 65 | ROUTER_ABI = [ 66 | {"inputs": [{"internalType": "uint256", "name": "amountOutMin", "type": "uint256"}, {"internalType": "address[]", "name": "path", "type": "address[]"}, {"internalType": "address", "name": "to", "type": "address"}, {"internalType": "uint256", "name": "deadline", "type": "uint256"}], "name": "swapExactETHForTokens", "outputs": [{"internalType": "uint256[]", "name": "amounts", "type": "uint256[]"}], "stateMutability": "payable", "type": "function"}, 67 | {"inputs": [{"internalType": "uint256", "name": "amountIn", "type": "uint256"}, {"internalType": "uint256", "name": "amountOutMin", "type": "uint256"}, {"internalType": "address[]", "name": "path", "type": "address[]"}, {"internalType": "address", "name": "to", "type": "address"}, {"internalType": "uint256", "name": "deadline", "type": "uint256"}], "name": "swapExactTokensForETH", "outputs": [{"internalType": "uint256[]", "name": "amounts", "type": "uint256[]"}], "stateMutability": "nonpayable", "type": "function"} 68 | ] 69 | 70 | # Function to connect to RPC 71 | def connect_to_rpc(): 72 | for url in RPC_URLS: 73 | w3 = Web3(Web3.HTTPProvider(url)) 74 | if w3.is_connected(): 75 | return w3 76 | raise Exception(f"{Fore.RED}❌ Could not connect to any RPC{Style.RESET_ALL}") 77 | 78 | # Initialize web3 provider 79 | w3 = connect_to_rpc() 80 | ROUTER_ADDRESS = w3.to_checksum_address(ROUTER_ADDRESS) 81 | WMON_ADDRESS = w3.to_checksum_address(WMON_ADDRESS) 82 | TOKENS = {key: {**value, "address": w3.to_checksum_address(value["address"])} for key, value in TOKENS.items()} 83 | file_path = "pvkey.txt" 84 | 85 | # Function to read private keys from pvkey.txt 86 | def load_private_keys(file_path): 87 | try: 88 | with open(file_path, 'r') as file: 89 | keys = [line.strip() for line in file.readlines() if line.strip()] 90 | if not keys: 91 | raise ValueError("pvkey.txt is empty") 92 | return keys 93 | except FileNotFoundError: 94 | print(f"{Fore.RED}❌ pvkey.txt not found{Style.RESET_ALL}") 95 | return None 96 | except Exception as e: 97 | print(f"{Fore.RED}❌ Error reading pvkey.txt: {str(e)}{Style.RESET_ALL}") 98 | return None 99 | 100 | # Function to display pretty border 101 | def print_border(text, color=Fore.MAGENTA, width=60): 102 | print(f"{color}╔{'═' * (width - 2)}╗{Style.RESET_ALL}") 103 | print(f"{color}║ {text:^56} ║{Style.RESET_ALL}") 104 | print(f"{color}╚{'═' * (width - 2)}╝{Style.RESET_ALL}") 105 | 106 | # Function to display step 107 | def print_step(step, message): 108 | steps = {'approve': 'Approve Token', 'swap': 'Swap'} 109 | step_text = steps[step] 110 | print(f"{Fore.YELLOW}🔸 {Fore.CYAN}{step_text:<15}{Style.RESET_ALL} | {message}") 111 | 112 | # Generate random amount (0.001 - 0.01 MON) 113 | def get_random_amount(): 114 | return round(random.uniform(0.001, 0.01), 6) 115 | 116 | # Generate random delay (1-3 minutes) 117 | def get_random_delay(): 118 | return random.randint(60, 180) # Returns seconds 119 | 120 | # Function to approve token with retry 121 | async def approve_token(private_key, token_address, amount, decimals, max_retries=3): 122 | for attempt in range(max_retries): 123 | try: 124 | account = w3.eth.account.from_key(private_key) 125 | wallet = account.address[:8] + "..." 126 | token_contract = w3.eth.contract(address=token_address, abi=ERC20_ABI) 127 | symbol = token_contract.functions.symbol().call() 128 | 129 | print_step('approve', f'Checking approval for {symbol}') 130 | amount_in_decimals = w3.to_wei(amount, 'ether') if decimals == 18 else int(amount * 10**decimals) 131 | tx = token_contract.functions.approve(ROUTER_ADDRESS, amount_in_decimals).build_transaction({ 132 | 'from': account.address, 133 | 'gas': 100000, 134 | 'gasPrice': w3.eth.gas_price, 135 | 'nonce': w3.eth.get_transaction_count(account.address), 136 | }) 137 | 138 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 139 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 140 | await asyncio.sleep(2) 141 | receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=180) 142 | if receipt.status == 1: 143 | print_step('approve', f"{Fore.GREEN}✔ {symbol} approved{Style.RESET_ALL}") 144 | return amount_in_decimals 145 | else: 146 | raise Exception(f"Approve failed: Status {receipt.status}") 147 | except Exception as e: 148 | if "429 Client Error" in str(e) and attempt < max_retries - 1: 149 | delay = 2 ** attempt # Exponential backoff: 1s, 2s, 4s 150 | print_step('approve', f"{Fore.YELLOW}Rate limited, retrying in {delay} seconds...{Style.RESET_ALL}") 151 | await asyncio.sleep(delay) 152 | else: 153 | print_step('approve', f"{Fore.RED}✘ Failed: {str(e)}{Style.RESET_ALL}") 154 | raise 155 | 156 | # Function to swap Token to MON 157 | async def swap_token_to_mon(private_key, token_symbol, amount): 158 | token = TOKENS[token_symbol] 159 | try: 160 | account = w3.eth.account.from_key(private_key) 161 | wallet = account.address[:8] + "..." 162 | 163 | print_border(f"Swap {amount} {token_symbol} to MON | {wallet}", Fore.MAGENTA) 164 | 165 | amount_in_decimals = await approve_token(private_key, token['address'], amount, token['decimals']) 166 | 167 | router = w3.eth.contract(address=ROUTER_ADDRESS, abi=ROUTER_ABI) 168 | tx = router.functions.swapExactTokensForETH( 169 | amount_in_decimals, 0, [token['address'], WMON_ADDRESS], account.address, int(time.time()) + 600 170 | ).build_transaction({ 171 | 'from': account.address, 172 | 'gas': 300000, 173 | 'gasPrice': w3.eth.gas_price, 174 | 'nonce': w3.eth.get_transaction_count(account.address), 175 | }) 176 | 177 | print_step('swap', 'Sending swap transaction...') 178 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 179 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 180 | 181 | print_step('swap', f"Tx Hash: {Fore.YELLOW}{EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 182 | await asyncio.sleep(2) 183 | receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=180) 184 | 185 | if receipt.status == 1: 186 | print_step('swap', f"{Fore.GREEN}✔ Swap successful!{Style.RESET_ALL}") 187 | return True 188 | else: 189 | raise Exception(f"Transaction failed: Status {receipt.status}") 190 | except Exception as e: 191 | print_step('swap', f"{Fore.RED}✘ Failed: {str(e)}{Style.RESET_ALL}") 192 | return False 193 | 194 | # Function to swap MON to Token 195 | async def swap_mon_to_token(private_key, token_symbol, amount): 196 | token = TOKENS[token_symbol] 197 | try: 198 | account = w3.eth.account.from_key(private_key) 199 | wallet = account.address[:8] + "..." 200 | 201 | print_border(f"Swap {amount} MON to {token_symbol} | {wallet}", Fore.MAGENTA) 202 | 203 | tx = w3.eth.contract(address=ROUTER_ADDRESS, abi=ROUTER_ABI).functions.swapExactETHForTokens( 204 | 0, [WMON_ADDRESS, token['address']], account.address, int(time.time()) + 600 205 | ).build_transaction({ 206 | 'from': account.address, 207 | 'value': w3.to_wei(amount, 'ether'), 208 | 'gas': 300000, 209 | 'gasPrice': w3.eth.gas_price, 210 | 'nonce': w3.eth.get_transaction_count(account.address), 211 | }) 212 | 213 | print_step('swap', 'Sending swap transaction...') 214 | signed_tx = w3.eth.account.sign_transaction(tx, private_key) 215 | tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) 216 | 217 | print_step('swap', f"Tx Hash: {Fore.YELLOW}{EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 218 | await asyncio.sleep(2) 219 | receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=180) 220 | 221 | if receipt.status == 1: 222 | print_step('swap', f"{Fore.GREEN}✔ Swap successful!{Style.RESET_ALL}") 223 | return True 224 | else: 225 | raise Exception(f"Transaction failed: Status {receipt.status}") 226 | except Exception as e: 227 | print_step('swap', f"{Fore.RED}✘ Failed: {str(e)}{Style.RESET_ALL}") 228 | return False 229 | 230 | # Function to check balance with retry 231 | async def check_balance(private_key, max_retries=3): 232 | account = w3.eth.account.from_key(private_key) 233 | wallet = account.address[:8] + "..." 234 | print_border(f"💰 Balance | {wallet}", Fore.CYAN) 235 | 236 | try: 237 | mon_balance = w3.eth.get_balance(account.address) 238 | print_step('swap', f"MON: {Fore.CYAN}{w3.from_wei(mon_balance, 'ether')}{Style.RESET_ALL}") 239 | except Exception as e: 240 | print_step('swap', f"MON: {Fore.RED}Error reading balance - {str(e)}{Style.RESET_ALL}") 241 | 242 | for symbol, token in TOKENS.items(): 243 | for attempt in range(max_retries): 244 | try: 245 | token_contract = w3.eth.contract(address=token['address'], abi=ERC20_ABI) 246 | balance = token_contract.functions.balanceOf(account.address).call() 247 | print_step('swap', f"{symbol}: {Fore.CYAN}{balance / 10**token['decimals']}{Style.RESET_ALL}") 248 | break 249 | except Exception as e: 250 | if "429 Client Error" in str(e) and attempt < max_retries - 1: 251 | delay = 2 ** attempt # Exponential backoff: 1s, 2s, 4s 252 | print_step('swap', f"{Fore.YELLOW}{symbol}: Rate limited, retrying in {delay} seconds...{Style.RESET_ALL}") 253 | await asyncio.sleep(delay) 254 | else: 255 | print_step('swap', f"{symbol}: {Fore.RED}Error reading balance - {str(e)}{Style.RESET_ALL}") 256 | break 257 | await asyncio.sleep(1) # Delay between tokens 258 | 259 | # Function to perform random swap 260 | async def perform_random_swap(private_key): 261 | account = w3.eth.account.from_key(private_key) 262 | wallet = account.address[:8] + "..." 263 | is_mon_to_token = random.random() < 0.5 264 | token_symbols = list(TOKENS.keys()) 265 | token_symbol = random.choice(token_symbols) 266 | token = TOKENS[token_symbol] 267 | 268 | if is_mon_to_token: 269 | amount = get_random_amount() 270 | amount_in_wei = w3.to_wei(amount, 'ether') 271 | print_border(f"🎲 Random Swap: {amount} MON → {token_symbol} | {wallet}", Fore.YELLOW) 272 | return await swap_mon_to_token(private_key, token_symbol, amount) 273 | else: 274 | amount = get_random_amount() 275 | print_border(f"🎲 Random Swap: {amount} {token_symbol} → MON | {wallet}", Fore.YELLOW) 276 | return await swap_token_to_mon(private_key, token_symbol, amount) 277 | 278 | # Run swap cycle 279 | async def run_swap_cycle(cycles, private_keys): 280 | for account_idx, private_key in enumerate(private_keys, 1): 281 | account = w3.eth.account.from_key(private_key) 282 | wallet = account.address[:8] + "..." 283 | print_border(f"🏦 ACCOUNT {account_idx}/{len(private_keys)} | {wallet}", Fore.BLUE) 284 | await check_balance(private_key) 285 | 286 | for i in range(cycles): 287 | print_border(f"🔄 BEAN SWAP CYCLE {i + 1}/{cycles} | {wallet}", Fore.CYAN) 288 | success = await perform_random_swap(private_key) 289 | if success: 290 | await check_balance(private_key) 291 | 292 | if i < cycles - 1: 293 | delay = get_random_delay() 294 | print(f"\n{Fore.YELLOW}⏳ Waiting {delay / 60:.1f} minutes before next cycle...{Style.RESET_ALL}") 295 | await asyncio.sleep(delay) 296 | 297 | if account_idx < len(private_keys): 298 | delay = get_random_delay() 299 | print(f"\n{Fore.YELLOW}⏳ Waiting {delay / 60:.1f} minutes before next account...{Style.RESET_ALL}") 300 | await asyncio.sleep(delay) 301 | 302 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 303 | print(f"{Fore.GREEN}│ ALL DONE: {cycles} CYCLES FOR {len(private_keys)} ACCOUNTS{' ' * (32 - len(str(cycles)) - len(str(len(private_keys))))}│{Style.RESET_ALL}") 304 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 305 | 306 | # Main function 307 | async def run(): 308 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 309 | print(f"{Fore.GREEN}│ {'BEAN SWAP - MONAD TESTNET':^56} │{Style.RESET_ALL}") 310 | print(f"{Fore.GREEN}{'═' * 60}{Style.RESET_ALL}") 311 | 312 | private_keys = load_private_keys('pvkey.txt') 313 | if not private_keys: 314 | return 315 | 316 | print(f"{Fore.CYAN}👥 Accounts: {len(private_keys)}{Style.RESET_ALL}") 317 | 318 | while True: 319 | try: 320 | print_border("🔢 NUMBER OF CYCLES", Fore.YELLOW) 321 | cycles_input = input(f"{Fore.GREEN}➤ Enter number (default 5): {Style.RESET_ALL}") 322 | cycles = int(cycles_input) if cycles_input.strip() else 5 323 | if cycles <= 0: 324 | raise ValueError 325 | break 326 | except ValueError: 327 | print(f"{Fore.RED}❌ Please enter a valid number!{Style.RESET_ALL}") 328 | 329 | print(f"{Fore.YELLOW}🚀 Running {cycles} Bean swaps with random 1-3 minute delay for {len(private_keys)} accounts...{Style.RESET_ALL}") 330 | await run_swap_cycle(cycles, private_keys) 331 | 332 | if __name__ == "__main__": 333 | asyncio.run(run()) 334 | -------------------------------------------------------------------------------- /scripts/ambient.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import random 3 | from typing import Dict, List, Optional, Tuple 4 | from eth_account import Account 5 | from eth_abi import abi 6 | from decimal import Decimal 7 | from loguru import logger 8 | from web3 import AsyncWeb3, Web3 9 | import aiohttp 10 | from colorama import init, Fore, Style 11 | 12 | # Initialize colorama 13 | init(autoreset=True) 14 | 15 | # Constants 16 | RPC_URL = "https://testnet-rpc.monad.xyz/" 17 | EXPLORER_URL = "https://testnet.monadexplorer.com/tx/0x" 18 | AMBIENT_CONTRACT = "0x88B96aF200c8a9c35442C8AC6cd3D22695AaE4F0" 19 | ZERO_ADDRESS = "0x0000000000000000000000000000000000000000" 20 | POOL_IDX = 36000 21 | RESERVE_FLAGS = 0 22 | TIP = 0 23 | MAX_SQRT_PRICE = 21267430153580247136652501917186561137 24 | MIN_SQRT_PRICE = 65537 25 | BORDER_WIDTH = 80 26 | ATTEMPTS = 3 27 | PAUSE_BETWEEN_SWAPS = [5, 10] 28 | PAUSE_BETWEEN_ACTIONS = [5, 15] 29 | 30 | AMBIENT_TOKENS = { 31 | "usdt": {"address": "0x88b8E2161DEDC77EF4ab7585569D2415a1C1055D", "decimals": 6}, 32 | "usdc": {"address": "0xf817257fed379853cDe0fa4F97AB987181B1E5Ea", "decimals": 6}, 33 | "weth": {"address": "0xB5a30b0FDc5EA94A52fDc42e3E9760Cb8449Fb37", "decimals": 18}, 34 | "wbtc": {"address": "0xcf5a6076cfa32686c0Df13aBaDa2b40dec133F1d", "decimals": 8}, 35 | "seth": {"address": "0x836047a99e11F376522B447bffb6e3495Dd0637c", "decimals": 18}, 36 | } 37 | 38 | ERC20_ABI = [ 39 | { 40 | "inputs": [{"internalType": "address", "name": "account", "type": "address"}], 41 | "name": "balanceOf", 42 | "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], 43 | "stateMutability": "view", 44 | "type": "function", 45 | }, 46 | { 47 | "inputs": [ 48 | {"internalType": "address", "name": "spender", "type": "address"}, 49 | {"internalType": "uint256", "name": "amount", "type": "uint256"}, 50 | ], 51 | "name": "approve", 52 | "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], 53 | "stateMutability": "nonpayable", 54 | "type": "function", 55 | }, 56 | { 57 | "inputs": [ 58 | {"internalType": "address", "name": "owner", "type": "address"}, 59 | {"internalType": "address", "name": "spender", "type": "address"}, 60 | ], 61 | "name": "allowance", 62 | "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], 63 | "stateMutability": "view", 64 | "type": "function", 65 | }, 66 | ] 67 | 68 | AMBIENT_ABI = [ 69 | { 70 | "inputs": [ 71 | {"internalType": "uint16", "name": "callpath", "type": "uint16"}, 72 | {"internalType": "bytes", "name": "cmd", "type": "bytes"}, 73 | ], 74 | "name": "userCmd", 75 | "outputs": [{"internalType": "bytes", "name": "", "type": "bytes"}], 76 | "stateMutability": "payable", 77 | "type": "function", 78 | } 79 | ] 80 | 81 | def print_border(text: str, color=Fore.CYAN, width=BORDER_WIDTH): 82 | text = text.strip() 83 | if len(text) > width - 4: 84 | text = text[:width - 7] + "..." 85 | padded_text = f" {text} ".center(width - 2) 86 | print(f"{color}┌{'─' * (width - 2)}┐{Style.RESET_ALL}") 87 | print(f"{color}│{padded_text}│{Style.RESET_ALL}") 88 | print(f"{color}└{'─' * (width - 2)}┘{Style.RESET_ALL}") 89 | 90 | def print_step(step: str, message: str): 91 | steps = { 92 | 'balance': 'BALANCE', 93 | 'faucet': 'GET TOKENS', 94 | 'approve': 'APPROVE', 95 | 'swap': 'SWAP' 96 | } 97 | step_text = steps[step] 98 | formatted_step = f"{Fore.YELLOW}🔸 {Fore.CYAN}{step_text:<15}{Style.RESET_ALL}" 99 | print(f"{formatted_step} | {message}") 100 | 101 | def print_completion_message(accounts: int, success_count: int): 102 | print(f"{Fore.GREEN}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 103 | print_border("AMBIENT SWAP - MONAD TESTNET", Fore.GREEN) 104 | print(f"{Fore.GREEN}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 105 | print(f"{Fore.YELLOW}🎉 Completed swap for {accounts} accounts{Style.RESET_ALL}") 106 | completion_msg = f"ALL DONE - {accounts} ACCOUNTS" 107 | print_border(completion_msg, Fore.GREEN) 108 | success_msg = f"SUCCESSFUL TRANSACTIONS: {success_count}" 109 | print_border(success_msg, Fore.CYAN) 110 | print(f"{Fore.GREEN}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 111 | 112 | class AmbientDex: 113 | def __init__(self, account_index: int, private_key: str, session: aiohttp.ClientSession): 114 | self.account_index = account_index 115 | self.web3 = AsyncWeb3(AsyncWeb3.AsyncHTTPProvider(RPC_URL)) 116 | self.account = Account.from_key(private_key) 117 | self.session = session 118 | self.router_contract = self.web3.eth.contract(address=AMBIENT_CONTRACT, abi=AMBIENT_ABI) 119 | 120 | async def get_gas_params(self) -> Dict[str, int]: 121 | """Get gas parameters from the network.""" 122 | latest_block = await self.web3.eth.get_block('latest') 123 | base_fee = latest_block['baseFeePerGas'] 124 | max_priority_fee = await self.web3.eth.max_priority_fee 125 | return { 126 | "maxFeePerGas": base_fee + max_priority_fee, 127 | "maxPriorityFeePerGas": max_priority_fee, 128 | } 129 | 130 | def convert_to_wei(self, amount: float, token: str) -> int: 131 | """Convert amount to wei based on token decimals.""" 132 | if token == "native": 133 | return self.web3.to_wei(amount, 'ether') 134 | decimals = AMBIENT_TOKENS[token.lower()]["decimals"] 135 | return int(Decimal(str(amount)) * Decimal(str(10 ** decimals))) 136 | 137 | def convert_from_wei(self, amount: int, token: str) -> float: 138 | """Convert from wei to token units.""" 139 | if token == "native": 140 | return float(self.web3.from_wei(amount, 'ether')) 141 | decimals = AMBIENT_TOKENS[token.lower()]["decimals"] 142 | return float(Decimal(str(amount)) / Decimal(str(10 ** decimals))) 143 | 144 | async def get_tokens_with_balance(self) -> List[Tuple[str, float]]: 145 | """Get list of tokens with balance greater than 0.""" 146 | tokens_with_balance = [] 147 | 148 | # Check native token (MON) balance 149 | native_balance = await self.web3.eth.get_balance(self.account.address) 150 | if native_balance > 0: 151 | native_amount = self.convert_from_wei(native_balance, "native") 152 | tokens_with_balance.append(("native", native_amount)) 153 | 154 | # Check other token balances 155 | for token in AMBIENT_TOKENS: 156 | try: 157 | token_contract = self.web3.eth.contract( 158 | address=self.web3.to_checksum_address(AMBIENT_TOKENS[token]["address"]), 159 | abi=ERC20_ABI 160 | ) 161 | balance = await token_contract.functions.balanceOf(self.account.address).call() 162 | if balance > 0: 163 | amount = self.convert_from_wei(balance, token) 164 | # Skip SETH and WETH if balance is too low 165 | if token.lower() in ["seth", "weth"] and amount < 0.001: 166 | continue 167 | tokens_with_balance.append((token, amount)) 168 | except Exception as e: 169 | logger.error(f"[{self.account_index}] Failed to get balance for {token}: {str(e)}") 170 | continue 171 | 172 | return tokens_with_balance 173 | 174 | async def generate_swap_data(self, token_in: str, token_out: str, amount_in_wei: int) -> Dict: 175 | """Tạo dữ liệu giao dịch swap cho Ambient DEX.""" 176 | for retry in range(ATTEMPTS): 177 | try: 178 | is_native = token_in == "native" 179 | token_address = ( 180 | AMBIENT_TOKENS[token_out.lower()]["address"] if is_native 181 | else AMBIENT_TOKENS[token_in.lower()]["address"] 182 | ) 183 | encode_data = abi.encode( 184 | ['address', 'address', 'uint16', 'bool', 'bool', 'uint256', 'uint8', 'uint256', 'uint256', 'uint8'], 185 | [ 186 | ZERO_ADDRESS, 187 | self.web3.to_checksum_address(token_address), 188 | POOL_IDX, 189 | is_native, 190 | is_native, 191 | amount_in_wei, 192 | TIP, 193 | MAX_SQRT_PRICE if is_native else MIN_SQRT_PRICE, 194 | 0, 195 | RESERVE_FLAGS 196 | ] 197 | ) 198 | function_selector = self.web3.keccak(text="userCmd(uint16,bytes)")[:4] 199 | cmd_params = abi.encode(['uint16', 'bytes'], [1, encode_data]) 200 | tx_data = function_selector.hex() + cmd_params.hex() 201 | 202 | gas_estimate = await self.web3.eth.estimate_gas({ 203 | 'to': AMBIENT_CONTRACT, 204 | 'from': self.account.address, 205 | 'data': '0x' + tx_data, 206 | 'value': amount_in_wei if is_native else 0 207 | }) 208 | 209 | return { 210 | "to": AMBIENT_CONTRACT, 211 | "data": '0x' + tx_data, 212 | "value": amount_in_wei if is_native else 0, 213 | "gas": int(gas_estimate * 1.1) 214 | } 215 | except Exception as e: 216 | await self._handle_error("generate_swap_data", e) 217 | raise Exception("Failed to generate swap data after retries") 218 | 219 | async def execute_transaction(self, tx_data: Dict) -> str: 220 | """Thực hiện giao dịch và chờ xác nhận.""" 221 | for retry in range(ATTEMPTS): 222 | try: 223 | nonce = await self.web3.eth.get_transaction_count(self.account.address) 224 | gas_params = await self.get_gas_params() 225 | transaction = { 226 | "from": self.account.address, 227 | "nonce": nonce, 228 | "type": 2, 229 | "chainId": 10143, 230 | **tx_data, 231 | **gas_params, 232 | } 233 | signed_txn = self.web3.eth.account.sign_transaction(transaction, self.account.key) 234 | tx_hash = await self.web3.eth.send_raw_transaction(signed_txn.rawTransaction) 235 | print_step('swap', "Waiting for transaction confirmation...", self.language) 236 | receipt = await self.web3.eth.wait_for_transaction_receipt(tx_hash, poll_latency=2) 237 | if receipt['status'] == 1: 238 | logger.success(f"[{self.account_index}] Transaction successful! TX: {EXPLORER_URL}{tx_hash.hex()}") 239 | return tx_hash.hex() 240 | else: 241 | raise Exception(f"Transaction failed: {EXPLORER_URL}{tx_hash.hex()}") 242 | except Exception as e: 243 | await self._handle_error("execute_transaction", e) 244 | raise Exception("Transaction execution failed after retries") 245 | 246 | async def approve_token(self, token: str, amount: int) -> Optional[str]: 247 | """Phê duyệt token cho Ambient DEX.""" 248 | for retry in range(ATTEMPTS): 249 | try: 250 | token_contract = self.web3.eth.contract( 251 | address=self.web3.to_checksum_address(AMBIENT_TOKENS[token.lower()]["address"]), 252 | abi=ERC20_ABI 253 | ) 254 | current_allowance = await token_contract.functions.allowance( 255 | self.account.address, AMBIENT_CONTRACT 256 | ).call() 257 | if current_allowance >= amount: 258 | logger.info(f"[{self.account_index}] Allowance sufficient for {token}") 259 | return None 260 | 261 | nonce = await self.web3.eth.get_transaction_count(self.account.address) 262 | gas_params = await self.get_gas_params() 263 | approve_tx = await token_contract.functions.approve( 264 | AMBIENT_CONTRACT, amount 265 | ).build_transaction({ 266 | 'from': self.account.address, 267 | 'nonce': nonce, 268 | 'type': 2, 269 | 'chainId': 10143, 270 | **gas_params, 271 | }) 272 | signed_txn = self.web3.eth.account.sign_transaction(approve_tx, self.account.key) 273 | tx_hash = await self.web3.eth.send_raw_transaction(signed_txn.rawTransaction) 274 | print_step('approve', f"Approving {self.convert_from_wei(amount, token):.4f} {token.upper()}...", self.language) 275 | receipt = await self.web3.eth.wait_for_transaction_receipt(tx_hash, poll_latency=2) 276 | if receipt['status'] == 1: 277 | logger.success(f"[{self.account_index}] Approval successful! TX: {EXPLORER_URL}{tx_hash.hex()}") 278 | print_step('approve', f"{Fore.GREEN}✔ Approved! TX: {EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}", self.language) 279 | return tx_hash.hex() 280 | raise Exception("Approval failed") 281 | except Exception as e: 282 | await self._handle_error("approve_token", e) 283 | raise Exception(f"Failed to approve {token} after retries") 284 | 285 | async def swap(self, percentage_to_swap: float = 100.0, swap_type: str = "regular") -> Optional[str]: 286 | """Thực hiện swap trên Ambient DEX.""" 287 | for retry in range(ATTEMPTS): 288 | try: 289 | tokens_with_balance = await self.get_tokens_with_balance() 290 | if not tokens_with_balance: 291 | print_step('swap', f"{Fore.RED}✘ No tokens with balance found{Style.RESET_ALL}", self.language) 292 | return None 293 | 294 | if swap_type == "collect": 295 | tokens_to_swap = [(t, b) for t, b in tokens_with_balance if t != "native"] 296 | if not tokens_to_swap: 297 | print_step('swap', f"{Fore.YELLOW}⚠ No tokens to collect to native{Style.RESET_ALL}", self.language) 298 | return None 299 | 300 | for token_in, balance in tokens_to_swap: 301 | try: 302 | if token_in.lower() == "seth": 303 | leave_amount = random.uniform(0.00001, 0.0001) 304 | balance -= leave_amount 305 | amount_wei = self.convert_to_wei(balance, token_in) 306 | await self.approve_token(token_in, amount_wei) 307 | await asyncio.sleep(random.uniform(*PAUSE_BETWEEN_SWAPS)) 308 | print_step('swap', f"Swapping {balance:.4f} {token_in.upper()} to MON...", self.language) 309 | tx_data = await self.generate_swap_data(token_in, "native", amount_wei) 310 | tx_hash = await self.execute_transaction(tx_data) 311 | if token_in != tokens_to_swap[-1][0]: 312 | await asyncio.sleep(random.uniform(5, 10)) 313 | except Exception as e: 314 | logger.error(f"[{self.account_index}] Failed to collect {token_in} to native: {str(e)}") 315 | continue 316 | print_step('swap', f"{Fore.GREEN}✔ Collection to native completed{Style.RESET_ALL}", self.language) 317 | return "Collection complete" 318 | 319 | else: # Regular swap 320 | token_in, balance = random.choice(tokens_with_balance) 321 | available_out_tokens = list(AMBIENT_TOKENS.keys()) + ["native"] 322 | available_out_tokens.remove(token_in) 323 | token_out = random.choice(available_out_tokens) 324 | 325 | if token_in == "native": 326 | percentage = Decimal(str(percentage_to_swap)) / Decimal('100') 327 | amount_wei = int(Decimal(str(self.convert_to_wei(balance, "native"))) * percentage) 328 | amount_token = self.convert_from_wei(amount_wei, "native") 329 | else: 330 | if token_in.lower() == "seth": 331 | leave_amount = random.uniform(0.00001, 0.0001) 332 | balance -= leave_amount 333 | amount_wei = self.convert_to_wei(balance, token_in) 334 | amount_token = balance 335 | await self.approve_token(token_in, amount_wei) 336 | await asyncio.sleep(random.uniform(*PAUSE_BETWEEN_SWAPS)) 337 | 338 | print_step('swap', f"Swapping {amount_token:.4f} {token_in.upper()} to {token_out.upper()}...", self.language) 339 | tx_data = await self.generate_swap_data(token_in, token_out, amount_wei) 340 | return await self.execute_transaction(tx_data) 341 | 342 | except Exception as e: 343 | await self._handle_error("swap", e) 344 | print_step('swap', f"{Fore.RED}✘ Swap failed after {ATTEMPTS} attempts{Style.RESET_ALL}", self.language) 345 | return None 346 | 347 | async def _handle_error(self, action: str, error: Exception) -> None: 348 | """Xử lý lỗi với pause ngẫu nhiên.""" 349 | pause = random.uniform(*PAUSE_BETWEEN_ACTIONS) 350 | logger.error(f"[{self.account_index}] Error in {action}: {error}. Sleeping for {pause:.2f}s") 351 | print_step(action, f"{Fore.RED}✘ Error: {str(error)}. Retrying in {pause:.2f}s{Style.RESET_ALL}") 352 | await asyncio.sleep(pause) 353 | 354 | async def run() -> None: 355 | """Run Ambient script with multiple private keys from pvkey.txt.""" 356 | try: 357 | with open("pvkey.txt", "r") as f: 358 | private_keys = [line.strip() for line in f if line.strip()] 359 | except FileNotFoundError: 360 | logger.error("File pvkey.txt not found!") 361 | print_border("ERROR: pvkey.txt not found!", Fore.RED) 362 | return 363 | 364 | if not private_keys: 365 | logger.error("No private keys found in pvkey.txt!") 366 | print_border("ERROR: No private keys found in pvkey.txt!", Fore.RED) 367 | return 368 | 369 | # Display title 370 | print(f"{Fore.GREEN}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 371 | print_border("AMBIENT SWAP - MONAD TESTNET", Fore.GREEN) 372 | print(f"{Fore.GREEN}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 373 | print(f"{Fore.CYAN}👥 Accounts: {len(private_keys):^76}{Style.RESET_ALL}") 374 | 375 | success_count = 0 376 | async with aiohttp.ClientSession() as session: 377 | for idx, private_key in enumerate(private_keys, start=1): 378 | wallet_short = Account.from_key(private_key).address[:8] + "..." 379 | account_msg = f"ACCOUNT {idx}/{len(private_keys)} - {wallet_short}" 380 | print_border(account_msg, Fore.BLUE) 381 | ambient = AmbientDex(idx, private_key, session) 382 | logger.info(f"Processing account {idx}/{len(private_keys)}: {ambient.account.address}") 383 | 384 | # Execute swap 385 | try: 386 | tx_hash = await ambient.swap(percentage_to_swap=100.0, swap_type="regular") 387 | if tx_hash: 388 | success_count += 1 389 | except Exception as e: 390 | logger.error(f"[{idx}] Failed to execute swap: {str(e)}") 391 | print_step('swap', f"{Fore.RED}✘ Swap failed: {str(e)}{Style.RESET_ALL}") 392 | 393 | # Pause between accounts 394 | if idx < len(private_keys): 395 | pause = random.uniform(10, 30) 396 | pause_msg = f"Waiting {pause:.2f}s before next account..." 397 | print(f"{Fore.YELLOW}⏳ {pause_msg:^76}{Style.RESET_ALL}") 398 | await asyncio.sleep(pause) 399 | 400 | # Display completion message 401 | print_completion_message(accounts=len(private_keys), success_count=success_count) 402 | 403 | if __name__ == "__main__": 404 | asyncio.run(run()) # Run with English by default 405 | -------------------------------------------------------------------------------- /scripts/bima.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import random 3 | from typing import Dict, List 4 | from eth_account import Account 5 | from eth_account.messages import encode_defunct 6 | from loguru import logger 7 | import aiohttp 8 | from web3 import AsyncWeb3, Web3 9 | from colorama import init, Fore, Style 10 | 11 | # Initialize colorama 12 | init(autoreset=True) 13 | 14 | # Define constants 15 | RPC_URL = "https://testnet-rpc.monad.xyz/" 16 | EXPLORER_URL = "https://testnet.monadexplorer.com/tx/0x" 17 | FAUCET_ADDRESS = "0xF2B87A9C773f468D4C9d1172b8b2C713f9481b80" 18 | bmBTC = Web3.to_checksum_address("0x0bb0aa6aa3a3fd4f7a43fb5e3d90bf9e6b4ef799") 19 | SPENDER_ADDRESS = Web3.to_checksum_address("0x07c4b0db9c020296275dceb6381397ac58bbf5c7") 20 | ATTEMPTS = 3 21 | PAUSE_BETWEEN_SWAPS = [5, 10] 22 | RANDOM_PAUSE_BETWEEN_ACTIONS = [5, 15] 23 | LEND = True 24 | PERCENT_OF_BALANCE_TO_LEND = [20, 30] 25 | BORDER_WIDTH = 80 26 | 27 | # Define ABI directly in file 28 | TOKEN_ABI = [ 29 | { 30 | "inputs": [{"internalType": "address", "name": "account", "type": "address"}], 31 | "name": "balanceOf", 32 | "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], 33 | "stateMutability": "view", 34 | "type": "function", 35 | }, 36 | { 37 | "inputs": [ 38 | {"internalType": "address", "name": "spender", "type": "address"}, 39 | {"internalType": "uint256", "name": "amount", "type": "uint256"}, 40 | ], 41 | "name": "approve", 42 | "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], 43 | "stateMutability": "nonpayable", 44 | "type": "function", 45 | }, 46 | ] 47 | 48 | FAUCET_ABI = [ 49 | { 50 | "inputs": [ 51 | {"internalType": "address", "name": "_tokenAddress", "type": "address"} 52 | ], 53 | "name": "getTokens", 54 | "outputs": [], 55 | "stateMutability": "nonpayable", 56 | "type": "function", 57 | } 58 | ] 59 | 60 | MARKET_PARAMS = ( 61 | Web3.to_checksum_address("0x01a4b3221e078106f9eb60c5303e3ba162f6a92e"), # loanToken 62 | bmBTC, # collateralToken 63 | Web3.to_checksum_address("0x7c47e0c69fb30fe451da48185c78f0c508b3e5b8"), # oracle 64 | Web3.to_checksum_address("0xc2d07bd8df5f33453e9ad4e77436b3eb70a09616"), # irm 65 | 900000000000000000, # lltv (0.9 в wei) 66 | ) 67 | 68 | LENDING_ABI = [ 69 | { 70 | "type": "function", 71 | "name": "supplyCollateral", 72 | "inputs": [ 73 | { 74 | "name": "marketParams", 75 | "type": "tuple", 76 | "components": [ 77 | {"name": "loanToken", "type": "address"}, 78 | {"name": "collateralToken", "type": "address"}, 79 | {"name": "oracle", "type": "address"}, 80 | {"name": "irm", "type": "address"}, 81 | {"name": "lltv", "type": "uint256"}, 82 | ], 83 | }, 84 | {"name": "assets", "type": "uint256"}, 85 | {"name": "onBehalf", "type": "address"}, 86 | {"name": "data", "type": "bytes"}, 87 | ], 88 | "outputs": [], 89 | "stateMutability": "nonpayable", 90 | } 91 | ] 92 | 93 | # Function to display a centered border with text 94 | def print_border(text: str, color=Fore.CYAN, width=BORDER_WIDTH): 95 | text = text.strip() 96 | if len(text) > width - 4: # -4 for the "│" characters and spaces 97 | text = text[:width - 7] + "..." # Truncate and add ... 98 | padded_text = f" {text} ".center(width - 2) 99 | print(f"{color}┌{'─' * (width - 2)}┐{Style.RESET_ALL}") 100 | print(f"{color}│{padded_text}│{Style.RESET_ALL}") 101 | print(f"{color}└{'─' * (width - 2)}┘{Style.RESET_ALL}") 102 | 103 | # Function to display step with wide format, no TX hash truncation 104 | def print_step(step: str, message: str): 105 | steps = { 106 | 'login': 'LOGIN', 107 | 'faucet': 'GET TOKENS', 108 | 'approve': 'APPROVE', 109 | 'lend': 'LEND', 110 | 'balance': 'BALANCE' 111 | } 112 | step_text = steps[step] 113 | formatted_step = f"{Fore.YELLOW}🔸 {Fore.CYAN}{step_text:<15}{Style.RESET_ALL}" 114 | print(f"{formatted_step} | {message}") 115 | 116 | # Function to display completion message 117 | def print_completion_message(accounts: int, success_count: int): 118 | print(f"{Fore.GREEN}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 119 | print_border("BIMA DEPOSIT - MONAD TESTNET", Fore.GREEN) 120 | print(f"{Fore.GREEN}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 121 | print(f"{Fore.YELLOW}🎉 {'Completed deposit for ' + str(accounts) + ' accounts':^76}{Style.RESET_ALL}") 122 | completion_msg = f"ALL DONE - {accounts} ACCOUNTS" 123 | print_border(completion_msg, Fore.GREEN) 124 | success_msg = f"SUCCESSFUL TRANSACTIONS: {success_count}" 125 | print_border(success_msg, Fore.CYAN) 126 | print(f"{Fore.GREEN}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 127 | 128 | 129 | class Bima: 130 | def __init__( 131 | self, 132 | account_index: int, 133 | proxy: str, 134 | private_key: str, 135 | session: aiohttp.ClientSession 136 | ): 137 | self.account_index = account_index 138 | self.proxy = proxy 139 | self.private_key = private_key 140 | self.session = session 141 | self.account = Account.from_key(private_key=private_key) 142 | self.web3 = AsyncWeb3(AsyncWeb3.AsyncHTTPProvider(RPC_URL)) 143 | 144 | async def login(self) -> bool: 145 | """Login to Bima.""" 146 | for retry in range(ATTEMPTS): 147 | try: 148 | message_to_sign, timestamp = await self._get_nonce() 149 | if not message_to_sign: 150 | raise ValueError("Message to sign is empty") 151 | 152 | signature = "0x" + self._get_signature(message_to_sign) 153 | headers = self._get_headers() 154 | json_data = {"signature": signature, "timestamp": int(timestamp)} 155 | 156 | print_step('login', "Attempting to log in...") 157 | async with self.session.post( 158 | "https://mainnet-api-v1.bima.money/bima/wallet/connect", 159 | headers=headers, 160 | json=json_data, 161 | ) as response: 162 | response.raise_for_status() 163 | logger.success(f"[{self.account_index}] Successfully logged in to Bima") 164 | print_step('login', f"{Fore.GREEN}✔ Login successful!{Style.RESET_ALL}") 165 | return True 166 | 167 | except Exception as e: 168 | await self._handle_error("login", e) 169 | print_step('login', f"{Fore.RED}✘ Login failed after {ATTEMPTS} attempts{Style.RESET_ALL}") 170 | return False 171 | 172 | async def lend(self) -> bool: 173 | """Perform lending on Bima.""" 174 | if not LEND: 175 | print_step('lend', f"{Fore.YELLOW}⚠ Lending is disabled{Style.RESET_ALL}") 176 | return False 177 | 178 | for retry in range(ATTEMPTS): 179 | try: 180 | logger.info(f"[{self.account_index}] Lending on Bima...") 181 | print_border(f"LENDING OPERATION - {self.account.address[:8]}", Fore.MAGENTA) 182 | token_contract = self.web3.eth.contract(address=bmBTC, abi=TOKEN_ABI) 183 | balance = await token_contract.functions.balanceOf(self.account.address).call() 184 | 185 | if balance == 0: 186 | raise ValueError("Token balance is 0") 187 | 188 | logger.info(f"[{self.account_index}] Token balance: {Web3.from_wei(balance, 'ether')} bmBTC") 189 | print_step('lend', f"Balance: {Fore.CYAN}{Web3.from_wei(balance, 'ether')} bmBTC{Style.RESET_ALL}") 190 | amount_to_lend = self._calculate_lend_amount(balance) 191 | 192 | print_step('approve', f"Approving {amount_to_lend / 10**18:.4f} bmBTC for lending") 193 | await self._approve_token(amount_to_lend) 194 | await asyncio.sleep(random.uniform(*PAUSE_BETWEEN_SWAPS)) 195 | 196 | print_step('lend', "Supplying collateral...") 197 | tx_hash = await self._supply_collateral(amount_to_lend) 198 | logger.success(f"[{self.account_index}] Successfully supplied collateral. TX: {EXPLORER_URL}{tx_hash.hex()}") 199 | print_step('lend', f"{Fore.GREEN}✔ Successfully supplied! TX: {EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 200 | return True 201 | 202 | except Exception as e: 203 | await self._handle_error("lend", e) 204 | print_step('lend', f"{Fore.RED}✘ Lending failed after {ATTEMPTS} attempts{Style.RESET_ALL}") 205 | return False 206 | 207 | async def get_faucet_tokens(self) -> bool: 208 | """Get tokens from Bima faucet.""" 209 | for retry in range(ATTEMPTS): 210 | try: 211 | if not await self.login(): 212 | raise ValueError("Failed to login to Bima") 213 | 214 | logger.info(f"[{self.account_index}] Getting tokens from Bima faucet...") 215 | print_border(f"FAUCET OPERATION - {self.account.address[:8]}", Fore.MAGENTA) 216 | print_step('faucet', "Requesting tokens from faucet...") 217 | 218 | # Check faucet bmBTC balance 219 | token_contract = self.web3.eth.contract(address=bmBTC, abi=TOKEN_ABI) 220 | faucet_balance = await token_contract.functions.balanceOf(FAUCET_ADDRESS).call() 221 | if faucet_balance == 0: 222 | logger.warning(f"[{self.account_index}] Faucet has no bmBTC balance") 223 | print_step('faucet', f"{Fore.RED}✘ Faucet is empty (0 bmBTC){Style.RESET_ALL}") 224 | return False 225 | 226 | logger.info(f"[{self.account_index}] Faucet balance: {Web3.from_wei(faucet_balance, 'ether')} bmBTC") 227 | print_step('faucet', f"Faucet balance: {Fore.CYAN}{Web3.from_wei(faucet_balance, 'ether')} bmBTC{Style.RESET_ALL}") 228 | 229 | # Check wallet MON balance 230 | mon_balance = await self.web3.eth.get_balance(self.account.address) 231 | if mon_balance < Web3.to_wei(0.01, 'ether'): 232 | logger.warning(f"[{self.account_index}] Insufficient MON balance: {Web3.from_wei(mon_balance, 'ether')} MON") 233 | print_step('faucet', f"{Fore.RED}✘ Insufficient MON: {Web3.from_wei(mon_balance, 'ether')} MON{Style.RESET_ALL}") 234 | return False 235 | 236 | print_step('faucet', f"Wallet MON: {Fore.CYAN}{Web3.from_wei(mon_balance, 'ether')} MON{Style.RESET_ALL}") 237 | 238 | # Try to build transaction 239 | contract = Web3().eth.contract(address=FAUCET_ADDRESS, abi=FAUCET_ABI) 240 | transaction = await self._build_transaction( 241 | contract.functions.getTokens(bmBTC), 242 | FAUCET_ADDRESS, 243 | ) 244 | 245 | # Try to call transaction to check for detailed errors 246 | try: 247 | await self.web3.eth.call(transaction) 248 | except Exception as call_error: 249 | error_str = str(call_error).lower() 250 | if "execution reverted" in error_str: 251 | logger.warning(f"[{self.account_index}] Faucet call failed: Daily limit reached") 252 | print_step('faucet', f"{Fore.YELLOW}⚠ Daily limit reached, try again in 24 hours{Style.RESET_ALL}") 253 | return False 254 | else: 255 | raise call_error 256 | 257 | gas_params = await self._get_gas_params() 258 | transaction.update({"gas": await self._estimate_gas(transaction), **gas_params}) 259 | 260 | tx_hash = await self._send_transaction(transaction) 261 | logger.success(f"[{self.account_index}] Successfully got tokens from Bima faucet. TX: {EXPLORER_URL}{tx_hash.hex()}") 262 | print_step('faucet', f"{Fore.GREEN}✔ Tokens received! TX: {EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 263 | return True 264 | 265 | except Exception as e: 266 | await self._handle_error("get_faucet_tokens", e) 267 | print_step('faucet', f"{Fore.RED}✘ Failed after {ATTEMPTS} attempts{Style.RESET_ALL}") 268 | return False 269 | 270 | async def _approve_token(self, amount: int) -> None: 271 | """Phê duyệt token để chi tiêu.""" 272 | contract = Web3().eth.contract(address=bmBTC, abi=TOKEN_ABI) 273 | gas_params = await self._get_gas_params() 274 | 275 | transaction = await self._build_transaction( 276 | contract.functions.approve(SPENDER_ADDRESS, amount), 277 | bmBTC, 278 | ) 279 | transaction.update({"gas": await self._estimate_gas(transaction), **gas_params}) 280 | 281 | tx_hash = await self._send_transaction(transaction) 282 | logger.success(f"[{self.account_index}] Successfully approved bmBTC. TX: {EXPLORER_URL}{tx_hash.hex()}") 283 | print_step('approve', f"{Fore.GREEN}✔ Approved! TX: {EXPLORER_URL}{tx_hash.hex()}{Style.RESET_ALL}") 284 | 285 | async def _supply_collateral(self, amount: int) -> bytes: 286 | """Cung cấp collateral cho lending.""" 287 | contract = Web3().eth.contract(address=SPENDER_ADDRESS, abi=LENDING_ABI) 288 | gas_params = await self._get_gas_params() 289 | 290 | transaction = await self._build_transaction( 291 | contract.functions.supplyCollateral( 292 | MARKET_PARAMS, 293 | amount, 294 | self.account.address, 295 | "0x", 296 | ), 297 | SPENDER_ADDRESS, 298 | ) 299 | transaction.update({"gas": await self._estimate_gas(transaction), **gas_params}) 300 | 301 | return await self._send_transaction(transaction) 302 | 303 | async def _get_nonce(self) -> tuple[str, str]: 304 | """Lấy nonce để đăng nhập.""" 305 | for retry in range(ATTEMPTS): 306 | try: 307 | async with self.session.get( 308 | "https://mainnet-api-v1.bima.money/bima/wallet/tip_info", 309 | headers=self._get_headers(), 310 | ) as response: 311 | response.raise_for_status() 312 | data = await response.json() 313 | return data["data"]["tip_info"], data["data"]["timestamp"] 314 | except Exception as e: 315 | await self._handle_error("_get_nonce", e) 316 | return "", "" 317 | 318 | def _get_headers(self) -> Dict[str, str]: 319 | """Trả về headers mặc định.""" 320 | return { 321 | "Accept": "application/json, text/plain, */*", 322 | "Accept-Language": "fr-CH,fr;q=0.9,en-US;q=0.8,en;q=0.7", 323 | "Connection": "keep-alive", 324 | "Content-Type": "application/json", 325 | "Origin": "https://bima.money", 326 | "Referer": "https://bima.money/", 327 | "Sec-Fetch-Dest": "empty", 328 | "Sec-Fetch-Mode": "cors", 329 | "Sec-Fetch-Site": "same-site", 330 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36", 331 | "address": self.account.address, 332 | "sec-ch-ua": '"Not A(Brand";v="8", "Chromium";v="132", "Google Chrome";v="132"', 333 | "sec-ch-ua-mobile": "?0", 334 | "sec-ch-ua-platform": '"Windows"', 335 | } 336 | 337 | def _calculate_lend_amount(self, balance: int) -> int: 338 | """Tính toán số lượng token để lend.""" 339 | percent = random.uniform(*PERCENT_OF_BALANCE_TO_LEND) 340 | return int(balance * percent / 100) 341 | 342 | async def _get_gas_params(self) -> Dict[str, int]: 343 | """Lấy thông số gas từ mạng.""" 344 | latest_block = await self.web3.eth.get_block("latest") 345 | base_fee = latest_block["baseFeePerGas"] 346 | max_priority_fee = await self.web3.eth.max_priority_fee 347 | return { 348 | "maxFeePerGas": base_fee + max_priority_fee, 349 | "maxPriorityFeePerGas": max_priority_fee, 350 | } 351 | 352 | async def _estimate_gas(self, transaction: dict) -> int: 353 | """Ước lượng gas cho giao dịch.""" 354 | try: 355 | estimated = await self.web3.eth.estimate_gas(transaction) 356 | return int(estimated * 1.1) # Buffer 10% 357 | except Exception as e: 358 | logger.warning(f"[{self.account_index}] Gas estimation failed: {e}. Using default.") 359 | raise 360 | 361 | async def _build_transaction(self, function, to_address: str) -> Dict: 362 | """Xây dựng giao dịch cơ bản bất đồng bộ.""" 363 | nonce = await self.web3.eth.get_transaction_count(self.account.address, "latest") 364 | return { 365 | "from": self.account.address, 366 | "to": to_address, 367 | "data": function._encode_transaction_data(), 368 | "chainId": 10143, 369 | "type": 2, 370 | "value": 0, 371 | "nonce": nonce, 372 | } 373 | 374 | async def _send_transaction(self, transaction: Dict) -> bytes: 375 | """Gửi giao dịch đã ký.""" 376 | signed_txn = self.web3.eth.account.sign_transaction(transaction, self.private_key) 377 | tx_hash = await self.web3.eth.send_raw_transaction(signed_txn.rawTransaction) 378 | logger.info(f"[{self.account_index}] Waiting for transaction confirmation...") 379 | await self.web3.eth.wait_for_transaction_receipt(tx_hash) 380 | return tx_hash 381 | 382 | def _get_signature(self, message: str) -> str: 383 | """Tạo chữ ký cho message.""" 384 | encoded_msg = encode_defunct(text=message) 385 | signed_msg = Web3().eth.account.sign_message(encoded_msg, private_key=self.private_key) 386 | return signed_msg.signature.hex() 387 | 388 | async def _handle_error(self, action: str, error: Exception) -> None: 389 | """Xử lý lỗi với pause ngẫu nhiên.""" 390 | pause = random.uniform(*RANDOM_PAUSE_BETWEEN_ACTIONS) 391 | logger.error(f"[{self.account_index}] Error in {action}: {error}. Sleeping for {pause:.2f}s") 392 | print_step(action, f"{Fore.RED}✘ Error: {str(error)}. Retrying in {pause:.2f}s{Style.RESET_ALL}") 393 | await asyncio.sleep(pause) 394 | 395 | 396 | async def run() -> None: 397 | """Run Bima script with multiple private keys from pvkey.txt.""" 398 | try: 399 | with open("pvkey.txt", "r") as f: 400 | private_keys = [line.strip() for line in f if line.strip()] 401 | except FileNotFoundError: 402 | logger.error("File pvkey.txt not found!") 403 | print_border("ERROR: pvkey.txt not found!", Fore.RED) 404 | return 405 | 406 | if not private_keys: 407 | logger.error("No private keys found in pvkey.txt!") 408 | print_border("ERROR: No private keys found in pvkey.txt!", Fore.RED) 409 | return 410 | 411 | # Display opening title 412 | print(f"{Fore.GREEN}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 413 | print_border("BIMA DEPOSIT - MONAD TESTNET", Fore.GREEN) 414 | print(f"{Fore.GREEN}{'═' * BORDER_WIDTH}{Style.RESET_ALL}") 415 | print(f"{Fore.CYAN}👥 {'Accounts'}: {len(private_keys):^76}{Style.RESET_ALL}") 416 | 417 | success_count = 0 418 | async with aiohttp.ClientSession() as session: 419 | for idx, private_key in enumerate(private_keys, start=1): 420 | wallet_short = Account.from_key(private_key).address[:8] + "..." 421 | account_msg = f"ACCOUNT {idx}/{len(private_keys)} - {wallet_short}" 422 | print_border(account_msg, Fore.BLUE) 423 | bima = Bima(idx, proxy="", private_key=private_key, session=session) 424 | logger.info(f"Processing account {idx}/{len(private_keys)}: {bima.account.address}") 425 | 426 | # Check wallet bmBTC balance 427 | token_contract = bima.web3.eth.contract(address=bmBTC, abi=TOKEN_ABI) 428 | wallet_balance = await token_contract.functions.balanceOf(bima.account.address).call() 429 | print_step('balance', f"Balance: {Fore.CYAN}{Web3.from_wei(wallet_balance, 'ether')} bmBTC{Style.RESET_ALL}") 430 | 431 | # Perform tasks in order 432 | if wallet_balance == 0: 433 | faucet_success = await bima.get_faucet_tokens() 434 | if not faucet_success: 435 | continue # Skip if faucet fails (out of tokens or daily limit) 436 | else: 437 | logger.info(f"[{bima.account_index}] Wallet already has bmBTC, skipping faucet") 438 | print_step('faucet', f"{Fore.YELLOW}⚠ Wallet has {Web3.from_wei(wallet_balance, 'ether')} bmBTC, skipping faucet{Style.RESET_ALL}") 439 | 440 | # Continue with lending if wallet has tokens or faucet was successful 441 | if await bima.lend(): 442 | success_count += 1 443 | 444 | # Pause between accounts 445 | if idx < len(private_keys): 446 | pause = random.uniform(10, 30) 447 | pause_msg = f"Waiting {pause:.2f}s before next account..." 448 | print(f"{Fore.YELLOW}⏳ {pause_msg:^76}{Style.RESET_ALL}") 449 | await asyncio.sleep(pause) 450 | 451 | # Display completion message 452 | print_completion_message(accounts=len(private_keys), success_count=success_count) 453 | 454 | 455 | if __name__ == "__main__": 456 | asyncio.run(run()) # Run with English by default 457 | --------------------------------------------------------------------------------