├── private_keys.txt ├── README.md ├── config.py ├── 02_withdrawal.py └── 01_deposit.py /private_keys.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Скрипт бриджит ETH из Mainnet в zkSync Era и обратно (https://portal.zksync.io/bridge) 2 | 3 | # Настройка config.py и данных : 4 | 1. В файл `private_keys.txt` выписываем приватные ключи кошельков построчно. 5 | 2. В файле `config.py` меняем значения переменных под себя (подробнее в самом файле) 6 | 7 | # Запуск : 8 | 1. Команда отправляет ETH из сети Mainnet в сеть zkSync Era. 9 | ``` 10 | python 01_deposit.py 11 | ``` 12 | 2. Команда отправляет ETH из сети zkSync Era обратно в сеть Mainnet (Примечание: сейчас вывод занимает 24 часа) 13 | ``` 14 | python 02_withdrawal.py 15 | ``` 16 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | from eth_account import Account 2 | from eth_account.signers.local import LocalAccount 3 | from web3 import Web3 4 | from zksync2.core.types import Token, EthBlockParams 5 | from zksync2.module.module_builder import ZkSyncBuilder 6 | from zksync2.manage_contracts.zksync_contract import ZkSyncContract 7 | from zksync2.provider.eth_provider import EthereumProvider 8 | 9 | from termcolor import cprint 10 | import time 11 | import random 12 | from tqdm import tqdm 13 | from loguru import logger 14 | import telebot 15 | 16 | # PRC провайдеры 17 | ZKSYNC_URL = "https://mainnet.era.zksync.io" 18 | ETH_URL = "https://rpc.ankr.com/eth" 19 | # ZKSYNC_URL = "https://zksync2-testnet.zksync.dev" 20 | # ETH_URL = "https://rpc.ankr.com/eth_goerli" 21 | 22 | # Кол-во ETH для отправки, значение рандомно выберется между MIN_AMOUNT и MAX_AMOUNT. 23 | MIN_AMOUNT = 0.001 24 | MAX_AMOUNT = 0.003 25 | 26 | # Значение GWEI при котором совершится транзакция, иначе будет ждать. 27 | # Если значение пустое, то будет использован текущий GWEI сети 28 | GWEI = 21 #'' 29 | 30 | # Пауза выполения скрипта между кошельками (рандомно между SLEEP_TIME_MIN и SLEEP_TIME_MAX) 31 | SLEEP_TIME_MIN = 100 32 | SLEEP_TIME_MAX = 300 33 | 34 | # настройка отправки результатов в тг бота 35 | TG_BOT_SEND = False # True / False. Если True, тогда будет отправлять результаты 36 | TG_TOKEN = '' # токен от тг-бота 37 | TG_ID = 000000000 # id твоего телеграмма, узнать его можно здесь : https://t.me/getmyid_bot 38 | 39 | STR_DONE = '✅ ' 40 | STR_CANCEL = '❌ ' 41 | 42 | list_send = [] 43 | def send_msg(): 44 | 45 | try: 46 | str_send = '\n'.join(list_send) 47 | bot = telebot.TeleBot(TG_TOKEN) 48 | bot.send_message(TG_ID, str_send, parse_mode='html') 49 | 50 | except Exception as error: 51 | logger.error(error) 52 | 53 | def sleeping(from_sleep, to_sleep): 54 | 55 | x = random.randint(from_sleep, to_sleep) 56 | for i in tqdm(range(x), desc='sleep ', bar_format='{desc}: {n_fmt}/{total_fmt}'): 57 | time.sleep(1) -------------------------------------------------------------------------------- /02_withdrawal.py: -------------------------------------------------------------------------------- 1 | from web3.middleware import geth_poa_middleware 2 | from zksync2.transaction.transaction_builders import TxWithdraw 3 | from config import * 4 | 5 | 6 | web3 = ZkSyncBuilder.build(ZKSYNC_URL) 7 | eth_web3 = Web3(Web3.HTTPProvider(ETH_URL)) 8 | 9 | def withdrawal(privatekey): 10 | 11 | try: 12 | 13 | account: LocalAccount = Account.from_key(privatekey) 14 | 15 | amount = web3.zksync.get_balance(account.address, EthBlockParams.LATEST.value) 16 | # amount = round(random.uniform(MIN_AMOUNT, MAX_AMOUNT), 8) 17 | 18 | # eth_web3.middleware_onion.inject(geth_poa_middleware, layer=0) 19 | 20 | eth_balance = eth_web3.eth.get_balance(account.address) 21 | logger.info(f"Eth: balance: {Web3.from_wei(eth_balance, 'ether')}") 22 | 23 | eth_provider = EthereumProvider(web3, 24 | eth_web3, 25 | account) 26 | withdrawal = TxWithdraw(web3=web3, 27 | token=Token.create_eth(), 28 | amount=Web3.to_wei(amount, "ether"), 29 | gas_limit=0, # unknown 30 | account=account) 31 | estimated_gas = web3.zksync.eth_estimate_gas(withdrawal.tx) 32 | tx = withdrawal.estimated_gas(estimated_gas) 33 | signed = account.sign_transaction(tx) 34 | tx_hash = web3.zksync.send_raw_transaction(signed.rawTransaction) 35 | logger.info(f"ZkSync Tx: https://goerli.explorer.zksync.io/tx/{web3.to_hex(tx_hash)}") 36 | list_send.append(f'{STR_DONE}zkSync Era withdrawal | {account.address}') 37 | # zks_receipt = web3.zksync.wait_finalized(tx_hash, timeout=3660, poll_latency=0.5) 38 | # logger.info(f"ZkSync Tx status: {zks_receipt['status']}") 39 | # tx_receipt = eth_provider.finalize_withdrawal(zks_receipt["transactionHash"]) 40 | # logger.info(f"Finalize withdrawal, Tx status: {tx_receipt['status']}") 41 | 42 | # prev = eth_balance 43 | # eth_balance = eth_web3.eth.get_balance(account.address) 44 | # logger.info(f"Eth: balance: {Web3.from_wei(eth_balance, 'ether')}") 45 | 46 | # fee = tx_receipt['gasUsed'] * tx_receipt['effectiveGasPrice'] 47 | # withdraw_absolute = Web3.to_wei(amount, 'ether') - fee 48 | # diff = eth_balance - prev 49 | # if withdraw_absolute == diff: 50 | # logger.success(f"Withdrawal including tx fee is passed | Eth diff with fee included: {Web3.from_wei(diff, 'ether')}") 51 | # list_send.append(f'{STR_DONE}zkSync Era withdrawal | {account.address}') 52 | # else: 53 | # logger.error(f"Withdrawal failed | Eth diff with fee included: {Web3.from_wei(diff, 'ether')}") 54 | # list_send.append(f'{STR_CANCEL}zkSync Era withdrawal | {account.address}') 55 | 56 | except Exception as error: 57 | logger.error(f'Withdrawal ETH from ZkSync Era| {error}') 58 | list_send.append(f'{STR_CANCEL}zkSync Era withdrawal | {account.address}') 59 | 60 | if __name__ == "__main__": 61 | 62 | with open("private_keys.txt", "r") as f: 63 | keys_list = [row.strip() for row in f] 64 | 65 | random.shuffle(keys_list) 66 | 67 | for privatekey in keys_list: 68 | cprint(f'\n=============== start : {privatekey} ===============', 'yellow') 69 | withdrawal(privatekey) 70 | sleep = random.randint(SLEEP_TIME_MIN, SLEEP_TIME_MAX) 71 | sleeping(sleep,sleep) 72 | 73 | if TG_BOT_SEND == True: 74 | send_msg() -------------------------------------------------------------------------------- /01_deposit.py: -------------------------------------------------------------------------------- 1 | from config import * 2 | 3 | 4 | zk_web3 = ZkSyncBuilder.build(ZKSYNC_URL) 5 | eth_web3 = Web3(Web3.HTTPProvider(ETH_URL)) 6 | 7 | def deposit(privatekey): 8 | 9 | try: 10 | amount = round(random.uniform(MIN_AMOUNT, MAX_AMOUNT), 8) 11 | 12 | account: LocalAccount = Account.from_key(privatekey) 13 | 14 | eth_provider = EthereumProvider(zk_web3, eth_web3, account) 15 | 16 | gas_price = eth_web3.eth.gas_price 17 | gas_limit = 710000 18 | 19 | print(f"Executing deposit transaction on L1 network, amount {amount}") 20 | operator_tip = eth_provider.get_base_cost(gas_limit=gas_limit, gas_per_pubdata_byte=800,gas_price=gas_price) 21 | 22 | l1_tx_receipt = eth_provider.deposit(token=Token.create_eth(), 23 | amount=Web3.to_wei(amount, 'ether'), 24 | l2_gas_limit=gas_limit, 25 | gas_price=gas_price, 26 | gas_per_pubdata_byte=800, 27 | operator_tip=operator_tip) 28 | 29 | if not l1_tx_receipt["status"]: 30 | logger.error(f"https://etherscan.io/tx//{l1_tx_receipt['transactionHash'].hex()}") 31 | list_send.append(f'{STR_CANCEL}zkSync Era deposit | {account.address}') 32 | return 33 | 34 | logger.success(f"https://etherscan.io/tx//tx/{l1_tx_receipt['transactionHash'].hex()}") 35 | list_send.append(f'{STR_DONE}zkSync Era deposit | {account.address}') 36 | 37 | # zksync_contract = ZkSyncContract(zk_web3.zksync.main_contract_address, eth_web3, account) 38 | 39 | # l2_hash = zk_web3.zksync.get_l2_hash_from_priority_op(l1_tx_receipt, zksync_contract) 40 | 41 | # print("Waiting for deposit transaction on L2 network to be finalized (5-7 minutes)") 42 | # l2_tx_receipt = zk_web3.zksync.wait_for_transaction_receipt(transaction_hash=l2_hash, 43 | # timeout=360, 44 | # poll_latency=10) 45 | 46 | # return l1_tx_receipt['transactionHash'].hex() , l2_tx_receipt['transactionHash'].hex() 47 | 48 | except Exception as error: 49 | logger.error(f'Deposit ETH to ZkSync Era| {error}') 50 | list_send.append(f'{STR_CANCEL}zkSync Era deposit | {account.address}') 51 | 52 | if __name__ == "__main__": 53 | 54 | with open("private_keys.txt", "r") as f: 55 | keys_list = [row.strip() for row in f] 56 | 57 | random.shuffle(keys_list) 58 | 59 | for privatekey in keys_list: 60 | cprint(f'\n=============== start : {privatekey} ===============', 'yellow') 61 | 62 | if GWEI == "": 63 | deposit(privatekey) 64 | else: 65 | stop_this_shit = False 66 | while not stop_this_shit: 67 | gas_price = eth_web3.eth.gas_price 68 | gwei_gas_price = eth_web3.from_wei(gas_price, 'gwei') 69 | 70 | if gwei_gas_price <= GWEI: 71 | deposit(privatekey) 72 | stop_this_shit = True 73 | else: 74 | logger.info(f'Waitting gas value {GWEI}(current gas {gwei_gas_price})') 75 | sleeping(30,30) 76 | 77 | sleep = random.randint(SLEEP_TIME_MIN, SLEEP_TIME_MAX) 78 | sleeping(sleep,sleep) 79 | 80 | if TG_BOT_SEND == True: 81 | send_msg() --------------------------------------------------------------------------------