├── data ├── proxies.txt ├── wallets.txt ├── recipients.txt └── abi │ ├── erc20.json │ └── abi.py ├── results ├── debank.txt ├── debank.csv └── web3_balances.csv ├── requirements.txt ├── MAIN.py ├── README.md ├── web3_checker.py ├── config.py ├── setting.py ├── debank.py └── utils.py /data/proxies.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/wallets.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /results/debank.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /results/debank.csv: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /data/recipients.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /results/web3_balances.csv: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiodns==3.0.0 2 | aiohttp==3.8.4 3 | aiosignal==1.3.1 4 | async-timeout==4.0.2 5 | attrs==23.1.0 6 | bitarray==2.7.3 7 | ccxt==3.0.78 8 | certifi==2022.12.7 9 | cffi==1.15.1 10 | charset-normalizer==3.1.0 11 | cryptography==40.0.2 12 | cytoolz==0.12.1 13 | eth-abi==4.0.0 14 | eth-account==0.8.0 15 | eth-hash==0.5.1 16 | eth-keyfile==0.6.1 17 | eth-keys==0.4.0 18 | eth-rlp==0.3.0 19 | eth-typing==3.3.0 20 | eth-utils==2.1.0 21 | frozenlist==1.3.3 22 | hexbytes==0.3.0 23 | idna==3.4 24 | jsonschema==4.17.3 25 | loguru==0.7.0 26 | lru-dict==1.1.8 27 | multidict==6.0.4 28 | parsimonious==0.9.0 29 | protobuf==4.22.3 30 | pycares==4.3.0 31 | pycparser==2.21 32 | pycryptodome==3.17 33 | pyrsistent==0.19.3 34 | pyTelegramBotAPI==4.11.0 35 | pyuseragents==1.0.5 36 | regex==2023.3.23 37 | requests==2.29.0 38 | rlp==3.0.0 39 | tabulate==0.9.0 40 | termcolor==2.3.0 41 | toolz==0.12.0 42 | tqdm==4.65.0 43 | urllib3==1.26.15 44 | web3==6.2.0 45 | websockets==11.0.2 46 | yarl==1.9.2 47 | -------------------------------------------------------------------------------- /MAIN.py: -------------------------------------------------------------------------------- 1 | from config import * 2 | from utils import * 3 | from web3_checker import * 4 | from debank import * 5 | 6 | def start_module(module, key=''): 7 | 8 | if module == 1: 9 | web3_check() 10 | 11 | if module == 2: 12 | start_debank() 13 | 14 | if module == 3: 15 | exchange_withdraw(key) 16 | 17 | if module == 4: 18 | okx_withdraw(key) 19 | 20 | if module == 5: 21 | transfer(key) 22 | 23 | if module == 6: 24 | inch_swap(key) 25 | 26 | if module == 7: 27 | orbiter_bridge(key) 28 | 29 | if module == 8: 30 | woofi(key) 31 | 32 | 33 | 34 | if __name__ == "__main__": 35 | 36 | cprint(RUN_TEXT, RUN_COLOR) 37 | cprint(f'\nsubscribe to us : https://t.me/hodlmodeth\n', RUN_COLOR) 38 | 39 | MODULE = int(MODULE) 40 | 41 | if MODULE in [1, 2]: 42 | start_module(MODULE) 43 | 44 | else: 45 | 46 | if RANDOM_WALLETS == True: random.shuffle(WALLETS) 47 | 48 | zero = 0 49 | for key in WALLETS: 50 | zero += 1 51 | 52 | wallet = evm_wallet(key) 53 | list_send.append(f'{zero}/{len(WALLETS)} : {wallet}\n') 54 | cprint(f'\n{zero}/{len(WALLETS)} : {wallet}\n', 'white') 55 | 56 | start_module(MODULE, key) 57 | 58 | if TG_BOT_SEND == True: 59 | send_msg() # отправляем результат в телеграм 60 | list_send.clear() 61 | 62 | if IS_SLEEP == True: 63 | sleeping(SLEEP_FROM, SLEEP_TO) 64 | 65 | 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Typing SVG](https://readme-typing-svg.herokuapp.com?color=%2336BCF7&lines=All-in-one+V2)](https://git.io/typing-svg) 2 | 3 | Идеальный скрипт-V2 для ведения фермы. Освоив его, ты сможешь (идет перечисление модулей) : 4 | 5 | 1. web3_checker : очень быстро (асинка) смотрит баланс монеты в любой evm сети. 6 | 2. debank_checker : около_быстро (асинка) смотрит все токены, нфт и протоколы во всех evm сетях (которые доступны на самом [debank](https://debank.com/)). 7 | 3. exchange_withdraw : вывод монет с бирж : binance, mexc, kucoin, bybit, huobi. 8 | 4. okx_withdraw : вывод с биржи okx + в подарок вывод с субов. отдельным модулем из-за функции вывода с суб-аккаунтов. 9 | 5. transfer : вывод монет с кошельков в evm сетях (метамаск). 10 | 6. 1inch : свапы на 1inch во всех сетях, включая zksync era. 11 | 7. [orbiter](https://www.orbiter.finance/) : бридж eth во всех сетях, включая zksync era. во всех, кроме starknet и zksync lite. 12 | 8. [woofi](https://fi.woo.org/) : бриджи и свапы. бридж проходит через stargate (layerzero). универсален, доступны все монеты и сети, которые там есть. 13 | 14 | Дополнительная информация : 15 | 1. Вместо принтов сделал logger. 16 | 2. Добавил tg_sender. Все результаты прописываются не только в терминал, но и в тг-бота. 17 | 3. Для чекеров сделал csv файлы. 18 | 4. Сделал нормальные try exceptы. 19 | 5. Сделал проверку транзакций на фейл (check_status_tx). 20 | 6. Сделал универсальный апрув и предварительную проверку на кол-во апрувнутых монет (check_allowance). то есть лишних апрувов делать не будет. 21 | 22 | # Настройка. 23 | 24 | 1. Вся настройка модулей и апи ключей делается в файле `setting.py`, их настройка описана в этом же файле. 25 | 2. В папке data есть 3 файла : `wallets.txt`, `recipients.txt`, `proxies.txt` : 26 | - `wallets.txt` - сюда записываем кошельки (приватники / адреса). 27 | - `recipients.txt` - сюда записываем адреса для трансфера, используется только в модуле transfer когда выводим с кошелька на адрес. 1 кошелек = 1 адрес. 28 | - `proxies.txt` - сюда записываем прокси, они используются только в debank чекере, без них он работать не будет. Чем больше, тем лучше. 29 | 3. Настраивать модули нужно в функциях value в файле `setting.py`. 30 | 4. Не забудь настроить тг-бота. Для этого в файле `setting.py` в переменную `TG_TOKEN` нужно вставить токен от тг бота. В переменную `TG_ID` нужно вставить свой id токен, узнать его можно здесь : https://t.me/getmyid_bot. 31 | 5. Запускать нужно файл `MAIN.py` 32 | 33 | Устанавливаем библиотеки : `pip3 install -r requirements.txt` 34 | 35 | Огромная просьба сначала все прочитать на 10 раз, все протестировать, погуглить и только потом задавать вопросы в наш код чат. В личку админам с вопросами по коду просьба не писать, они не ответят. 36 | 37 | Donate (evm) : `0xb7415DB78c886c67DBfB25D3Eb7fcd496dAf9021` or `donates-for-hodlmod.eth` 38 | 39 | Паблик : https://t.me/hodlmodeth. [ code ] чат : https://t.me/code_hodlmodeth. 40 | -------------------------------------------------------------------------------- /data/abi/erc20.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [], 4 | "name": "name", 5 | "outputs": [ 6 | { 7 | "internalType": "string", 8 | "name": "", 9 | "type": "string" 10 | } 11 | ], 12 | "stateMutability": "view", 13 | "type": "function" 14 | }, 15 | { 16 | "inputs": [], 17 | "name": "symbol", 18 | "outputs": [ 19 | { 20 | "internalType": "string", 21 | "name": "", 22 | "type": "string" 23 | } 24 | ], 25 | "stateMutability": "view", 26 | "type": "function" 27 | }, 28 | { 29 | "inputs": [], 30 | "name": "decimals", 31 | "outputs": [ 32 | { 33 | "internalType": "uint8", 34 | "name": "", 35 | "type": "uint8" 36 | } 37 | ], 38 | "stateMutability": "view", 39 | "type": "function" 40 | }, 41 | { 42 | "inputs": [], 43 | "name": "totalSupply", 44 | "outputs": [ 45 | { 46 | "internalType": "uint256", 47 | "name": "", 48 | "type": "uint256" 49 | } 50 | ], 51 | "stateMutability": "view", 52 | "type": "function" 53 | }, 54 | { 55 | "inputs": [ 56 | { 57 | "internalType": "address", 58 | "name": "account", 59 | "type": "address" 60 | } 61 | ], 62 | "name": "balanceOf", 63 | "outputs": [ 64 | { 65 | "internalType": "uint256", 66 | "name": "", 67 | "type": "uint256" 68 | } 69 | ], 70 | "stateMutability": "view", 71 | "type": "function" 72 | }, 73 | { 74 | "inputs": [ 75 | { 76 | "internalType": "address", 77 | "name": "recipient", 78 | "type": "address" 79 | }, 80 | { 81 | "internalType": "uint256", 82 | "name": "amount", 83 | "type": "uint256" 84 | } 85 | ], 86 | "name": "transfer", 87 | "outputs": [ 88 | { 89 | "internalType": "bool", 90 | "name": "", 91 | "type": "bool" 92 | } 93 | ], 94 | "stateMutability": "nonpayable", 95 | "type": "function" 96 | }, 97 | { 98 | "inputs": [ 99 | { 100 | "internalType": "address", 101 | "name": "sender", 102 | "type": "address" 103 | }, 104 | { 105 | "internalType": "address", 106 | "name": "recipient", 107 | "type": "address" 108 | }, 109 | { 110 | "internalType": "uint256", 111 | "name": "amount", 112 | "type": "uint256" 113 | } 114 | ], 115 | "name": "transferFrom", 116 | "outputs": [ 117 | { 118 | "internalType": "bool", 119 | "name": "", 120 | "type": "bool" 121 | } 122 | ], 123 | "stateMutability": "nonpayable", 124 | "type": "function" 125 | }, 126 | { 127 | "inputs": [ 128 | { 129 | "internalType": "address", 130 | "name": "spender", 131 | "type": "address" 132 | }, 133 | { 134 | "internalType": "uint256", 135 | "name": "amount", 136 | "type": "uint256" 137 | } 138 | ], 139 | "name": "approve", 140 | "outputs": [ 141 | { 142 | "internalType": "bool", 143 | "name": "", 144 | "type": "bool" 145 | } 146 | ], 147 | "stateMutability": "nonpayable", 148 | "type": "function" 149 | }, 150 | { 151 | "inputs": [ 152 | { 153 | "internalType": "address", 154 | "name": "owner", 155 | "type": "address" 156 | }, 157 | { 158 | "internalType": "address", 159 | "name": "spender", 160 | "type": "address" 161 | } 162 | ], 163 | "name": "allowance", 164 | "outputs": [ 165 | { 166 | "internalType": "uint256", 167 | "name": "", 168 | "type": "uint256" 169 | } 170 | ], 171 | "stateMutability": "view", 172 | "type": "function" 173 | }, 174 | { 175 | "anonymous": false, 176 | "inputs": [ 177 | { 178 | "indexed": true, 179 | "internalType": "address", 180 | "name": "from", 181 | "type": "address" 182 | }, 183 | { 184 | "indexed": true, 185 | "internalType": "address", 186 | "name": "to", 187 | "type": "address" 188 | }, 189 | { 190 | "indexed": false, 191 | "internalType": "uint256", 192 | "name": "value", 193 | "type": "uint256" 194 | } 195 | ], 196 | "name": "Transfer", 197 | "type": "event" 198 | }, 199 | { 200 | "anonymous": false, 201 | "inputs": [ 202 | { 203 | "indexed": true, 204 | "internalType": "address", 205 | "name": "owner", 206 | "type": "address" 207 | }, 208 | { 209 | "indexed": true, 210 | "internalType": "address", 211 | "name": "spender", 212 | "type": "address" 213 | }, 214 | { 215 | "indexed": false, 216 | "internalType": "uint256", 217 | "name": "value", 218 | "type": "uint256" 219 | } 220 | ], 221 | "name": "Approval", 222 | "type": "event" 223 | } 224 | ] -------------------------------------------------------------------------------- /web3_checker.py: -------------------------------------------------------------------------------- 1 | from config import * 2 | 3 | RESULT = { 4 | 'wallets' : [], 5 | 'balances' : [], 6 | } 7 | 8 | def evm_wallet(key): 9 | retry = 0 10 | while True: 11 | try: 12 | web3 = Web3(Web3.HTTPProvider(DATA['ethereum']['rpc'])) 13 | wallet = web3.eth.account.from_key(key).address 14 | return wallet 15 | except : 16 | retry += 1 17 | if retry >= 2: 18 | return key 19 | 20 | def round_to(num, digits=3): 21 | try: 22 | if num == 0: return 0 23 | scale = int(-math.floor(math.log10(abs(num - int(num))))) + digits - 1 24 | if scale < digits: scale = digits 25 | return round(num, scale) 26 | except: return num 27 | 28 | async def check_data_token(web3, token_address): 29 | 30 | try: 31 | 32 | token_contract = web3.eth.contract(address=Web3.to_checksum_address(token_address), abi=ERC20_ABI) 33 | decimals = await token_contract.functions.decimals().call() 34 | symbol = await token_contract.functions.symbol().call() 35 | 36 | return token_contract, decimals, symbol 37 | 38 | except Exception as error: 39 | 40 | logger.error(f'{error}') 41 | await asyncio.sleep(2) 42 | return await check_data_token(web3, token_address) 43 | 44 | async def check_balance(web3, privatekey, chain, address_contract): 45 | try: 46 | 47 | try: 48 | wallet = web3.eth.account.from_key(privatekey) 49 | wallet = wallet.address 50 | except Exception as error: 51 | wallet = privatekey 52 | 53 | if address_contract == '': # eth 54 | balance = await web3.eth.get_balance(web3.to_checksum_address(wallet)) 55 | token_decimal = 18 56 | else: 57 | token_contract, token_decimal, symbol = await check_data_token(web3, address_contract) 58 | balance = await token_contract.functions.balanceOf(web3.to_checksum_address(wallet)).call() 59 | 60 | human_readable = decimalToInt(balance, token_decimal) 61 | 62 | return human_readable 63 | 64 | except Exception as error: 65 | logger.error(f'{error}') 66 | await asyncio.sleep(1) 67 | return await check_balance(web3, privatekey, chain, address_contract) 68 | 69 | async def worker(privatekey, chain, address_contract): 70 | 71 | while True: 72 | try: 73 | web3 = Web3( 74 | AsyncHTTPProvider(DATA[chain]['rpc']), 75 | modules={"eth": (AsyncEth,)}, 76 | middlewares=[], 77 | ) 78 | break 79 | except Exception as error: 80 | cprint(error, 'red') 81 | await asyncio.sleep(1) 82 | 83 | 84 | balance = await check_balance(web3, privatekey, chain, address_contract) 85 | RESULT['wallets'].append({privatekey : balance}) 86 | RESULT['balances'].append(balance) 87 | 88 | async def main(chain, address_contract, wallets): 89 | 90 | tasks = [worker(wallet, chain, address_contract) for wallet in wallets] 91 | await asyncio.gather(*tasks) 92 | 93 | def send_result(min_balance, file_name, wallets_): 94 | 95 | small_balance = [] 96 | with open(f'{outfile}results/{file_name}.csv', 'w', newline='') as csvfile: 97 | spamwriter = csv.writer(csvfile, delimiter=',', quoting=csv.QUOTE_MINIMAL) 98 | 99 | spamwriter.writerow(['wallet', 'balance']) 100 | 101 | for address in wallets_: 102 | for data in RESULT['wallets']: 103 | for wallets in data.items(): 104 | wallet = wallets[0] 105 | balance = wallets[1] 106 | 107 | if wallet == address: 108 | if balance >= min_balance: 109 | balance = round_to(balance) 110 | cprint(f'{wallet} : {balance}', 'white') 111 | spamwriter.writerow([wallet, balance]) 112 | else: 113 | small_balance.append(wallet) 114 | 115 | sum_balance = sum(RESULT["balances"]) 116 | sum_balance = round_to(sum_balance) 117 | spamwriter.writerow(['total_balance', sum_balance]) 118 | 119 | cprint(f'total balance : {sum_balance}\n', 'green') 120 | 121 | if len(small_balance) != 0: 122 | cprint(f'\nBalance of these wallets < {min_balance} :', 'yellow') 123 | spamwriter.writerow([]) 124 | spamwriter.writerow(['small balance:']) 125 | for wallet in small_balance: 126 | cprint(wallet, 'white') 127 | spamwriter.writerow([wallet]) 128 | 129 | cprint(f'\nРезультаты записаны в файл : {outfile}results/{file_name}.csv\n', 'blue') 130 | 131 | 132 | def web3_check(): 133 | 134 | cprint(f'\nSTART WEB3 CHECKER\n', 'green') 135 | 136 | RESULT['wallets'].clear() 137 | RESULT['balances'].clear() 138 | 139 | wallets = [] 140 | for key in WALLETS: 141 | wallet = evm_wallet(key) 142 | wallets.append(wallet) 143 | 144 | chain, address_contract, min_balance, file_name = value_web3_checker() 145 | 146 | asyncio.run(main(chain, address_contract, wallets)) 147 | 148 | send_result(min_balance, file_name, wallets) 149 | 150 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | import requests, json, time, ccxt 2 | from ccxt import ExchangeError 3 | from loguru import logger 4 | from web3 import Web3, AsyncHTTPProvider 5 | from web3.eth import AsyncEth 6 | import asyncio, aiohttp 7 | from termcolor import cprint 8 | import random 9 | import telebot 10 | from tqdm import tqdm 11 | import hmac, base64 12 | import csv 13 | from pyuseragents import random as random_useragent 14 | from tabulate import tabulate 15 | import math 16 | import decimal 17 | 18 | from setting import * 19 | from data.abi.abi import * 20 | 21 | outfile = '' 22 | with open(f"{outfile}data/abi/erc20.json", "r") as file: 23 | ERC20_ABI = json.load(file) 24 | 25 | with open(f"{outfile}data/wallets.txt", "r") as f: 26 | WALLETS = [row.strip() for row in f] 27 | 28 | with open(f"{outfile}data/recipients.txt", "r") as f: 29 | RECIPIENTS = [row.strip() for row in f] 30 | 31 | with open(f"{outfile}data/proxies.txt", "r") as f: 32 | PROXIES = [row.strip() for row in f] 33 | 34 | # меняем рпс на свои 35 | DATA = { 36 | 'ethereum' : {'rpc': 'https://rpc.ankr.com/eth', 'scan': 'https://etherscan.io/tx', 'token': 'ETH'}, 37 | 38 | 'optimism' : {'rpc': 'https://rpc.ankr.com/optimism', 'scan': 'https://optimistic.etherscan.io/tx', 'token': 'ETH'}, 39 | 40 | 'bsc' : {'rpc': 'https://rpc.ankr.com/bsc', 'scan': 'https://bscscan.com/tx', 'token': 'BNB'}, 41 | 42 | 'polygon' : {'rpc': 'https://rpc.ankr.com/polygon', 'scan': 'https://polygonscan.com/tx', 'token': 'MATIC'}, 43 | 44 | 'polygon_zkevm' : {'rpc': 'https://zkevm-rpc.com', 'scan': 'https://zkevm.polygonscan.com/tx', 'token': 'ETH'}, 45 | 46 | 'arbitrum' : {'rpc': 'https://rpc.ankr.com/arbitrum', 'scan': 'https://arbiscan.io/tx', 'token': 'ETH'}, 47 | 48 | 'avalanche' : {'rpc': 'https://rpc.ankr.com/avalanche', 'scan': 'https://snowtrace.io/tx', 'token': 'AVAX'}, 49 | 50 | 'fantom' : {'rpc': 'https://rpc.ankr.com/fantom', 'scan': 'https://ftmscan.com/tx', 'token': 'FTM'}, 51 | 52 | 'nova' : {'rpc': 'https://nova.arbitrum.io/rpc', 'scan': 'https://nova.arbiscan.io/tx', 'token': 'ETH'}, 53 | 54 | 'zksync' : {'rpc': 'https://mainnet.era.zksync.io', 'scan': 'https://explorer.zksync.io/tx', 'token': 'ETH'}, 55 | } 56 | 57 | STR_DONE = '✅ ' 58 | STR_CANCEL = '❌ ' 59 | 60 | def intToDecimal(qty, decimal): 61 | return int(qty * int("".join(["1"] + ["0"]*decimal))) 62 | 63 | def decimalToInt(qty, decimal): 64 | return qty/ int("".join((["1"]+ ["0"]*decimal))) 65 | 66 | def call_json(result, outfile): 67 | with open(f"{outfile}.json", "w") as file: 68 | json.dump(result, file, indent=4, ensure_ascii=False) 69 | 70 | def sleeping(from_sleep, to_sleep): 71 | x = random.randint(from_sleep, to_sleep) 72 | for i in tqdm(range(x), desc='sleep ', bar_format='{desc}: {n_fmt}/{total_fmt}'): 73 | time.sleep(1) 74 | 75 | def recipients_evm(): 76 | try: 77 | wallets = {} 78 | zero = -1 79 | for evm in WALLETS: 80 | zero += 1 81 | wallets.update({evm : RECIPIENTS[zero]}) 82 | 83 | return wallets 84 | except Exception as error: 85 | # cprint(f'recipients_evm() error : {error}', 'red') 86 | return {} 87 | 88 | RECIPIENTS_WALLETS = recipients_evm() 89 | 90 | ORBITER_AMOUNT = { 91 | 'ethereum' : 0.000000000000009001, 92 | 'optimism' : 0.000000000000009007, 93 | 'bsc' : 0.000000000000009015, 94 | 'arbitrum' : 0.000000000000009002, 95 | 'nova' : 0.000000000000009016, 96 | 'polygon' : 0.000000000000009006, 97 | 'polygon_zkevm' : 0.000000000000009017, 98 | 'zksync' : 0.000000000000009014, 99 | 'starknet' : 0.000000000000009004, 100 | } 101 | 102 | ORBITER_AMOUNT_STR = { 103 | 'ethereum' : '9001', 104 | 'optimism' : '9007', 105 | 'bsc' : '9015', 106 | 'arbitrum' : '9002', 107 | 'nova' : '9016', 108 | 'polygon' : '9006', 109 | 'polygon_zkevm' : '9017', 110 | 'zksync' : '9014', 111 | 'starknet' : '9004', 112 | } 113 | 114 | LAYERZERO_CHAINS_ID = { 115 | 'avalanche' : 106, 116 | 'polygon' : 109, 117 | 'ethereum' : 101, 118 | 'bsc' : 102, 119 | 'arbitrum' : 110, 120 | 'optimism' : 111, 121 | 'fantom' : 112, 122 | 'aptos' : 108 123 | } 124 | 125 | # контракты бриджа 126 | WOOFI_BRIDGE_CONTRACTS = { 127 | 'avalanche' : '0x51AF494f1B4d3f77835951FA827D66fc4A18Dae8', 128 | 'polygon' : '0xAA9c15cd603428cA8ddD45e933F8EfE3Afbcc173', 129 | 'ethereum' : '0x9D1A92e601db0901e69bd810029F2C14bCCA3128', 130 | 'bsc' : '0x81004C9b697857fD54E137075b51506c739EF439', 131 | 'arbitrum' : '0x4AB421de52b3112D02442b040dd3DC73e8Af63b5', 132 | 'optimism' : '0xbeae1b06949d033da628ba3e5af267c3e740494b', 133 | 'fantom' : '0x72dc7fa5eeb901a34173C874A7333c8d1b34bca9', 134 | } 135 | 136 | # контракты свапа 137 | WOOFI_SWAP_CONTRACTS = { 138 | 'avalanche' : '0xC22FBb3133dF781E6C25ea6acebe2D2Bb8CeA2f9', 139 | 'polygon' : '0x817Eb46D60762442Da3D931Ff51a30334CA39B74', 140 | 'ethereum' : '', 141 | 'bsc' : '0x4f4Fd4290c9bB49764701803AF6445c5b03E8f06', 142 | 'arbitrum' : '0x9aed3a8896a85fe9a8cac52c9b402d092b629a30', 143 | 'optimism' : '0xEAf1Ac8E89EA0aE13E0f03634A4FF23502527024', 144 | 'fantom' : '0x382A9b0bC5D29e96c3a0b81cE9c64d6C8F150Efb', 145 | } 146 | 147 | # через что бриджим на woofi (usdc / usdt) 148 | WOOFI_PATH = { 149 | 'avalanche' : '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E', 150 | 'polygon' : '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', 151 | 'ethereum' : '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', 152 | 'bsc' : '0x55d398326f99059ff775485246999027b3197955', 153 | 'arbitrum' : '0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8', 154 | 'optimism' : '0x7f5c764cbc14f9669b88837ca1490cca17c31607', 155 | 'fantom' : '0x04068DA6C83AFCFA0e13ba15A6696662335D5B75', 156 | } 157 | 158 | text1 = ''' 159 | /$$ /$$ /$$$$$$ /$$$$$$$ /$$ /$$ /$$ /$$$$$$ /$$$$$$$ 160 | | $$ | $$ /$$__ $$| $$__ $$| $$ | $$$ /$$$ /$$__ $$| $$__ $$ 161 | | $$ | $$| $$ \ $$| $$ \ $$| $$ | $$$$ /$$$$| $$ \ $$| $$ \ $$ 162 | | $$$$$$$$| $$ | $$| $$ | $$| $$ | $$ $$/$$ $$| $$ | $$| $$ | $$ 163 | | $$__ $$| $$ | $$| $$ | $$| $$ | $$ $$$| $$| $$ | $$| $$ | $$ 164 | | $$ | $$| $$ | $$| $$ | $$| $$ | $$\ $ | $$| $$ | $$| $$ | $$ 165 | | $$ | $$| $$$$$$/| $$$$$$$/| $$$$$$$$| $$ \/ | $$| $$$$$$/| $$$$$$$/ 166 | |__/ |__/ \______/ |_______/ |________/|__/ |__/ \______/ |_______/ 167 | ''' 168 | 169 | text2 = ''' 170 | ___ ___ ___ ___ 171 | /\ \ /\ \ _____ /\ \ /\ \ _____ 172 | \:\ \ /::\ \ /::\ \ |::\ \ /::\ \ /::\ \ 173 | \:\ \ /:/\:\ \ /:/\:\ \ |:|:\ \ /:/\:\ \ /:/\:\ \ 174 | ___ /::\ \ /:/ \:\ \ /:/ \:\__\ ___ ___ __|:|\:\ \ /:/ \:\ \ /:/ \:\__\ 175 | /\ /:/\:\__\/:/__/ \:\__\/:/__/ \:|__|/\ \ /\__\/::::|_\:\__\/:/__/ \:\__\/:/__/ \:|__| 176 | \:\/:/ \/__/\:\ \ /:/ /\:\ \ /:/ /\:\ \ /:/ /\:\~~\ \/__/\:\ \ /:/ /\:\ \ /:/ / 177 | \::/__/ \:\ /:/ / \:\ /:/ / \:\ /:/ / \:\ \ \:\ /:/ / \:\ /:/ / 178 | \:\ \ \:\/:/ / \:\/:/ / \:\/:/ / \:\ \ \:\/:/ / \:\/:/ / 179 | \:\__\ \::/ / \::/ / \::/ / \:\__\ \::/ / \::/ / 180 | \/__/ \/__/ \/__/ \/__/ \/__/ \/__/ \/__/ 181 | ''' 182 | 183 | texts = [text1, text2] 184 | colors = ['green', 'yellow', 'blue', 'magenta', 'cyan'] 185 | 186 | RUN_TEXT = random.choice(texts) 187 | RUN_COLOR = random.choice(colors) 188 | -------------------------------------------------------------------------------- /setting.py: -------------------------------------------------------------------------------- 1 | ''' 2 | 3 | MODULE : 4 | 5 | 1. web3_checker 6 | 2. debank checker 7 | 3. exchange withdraw : вывод с биржи 8 | 4. okx withdraw : вывод с okx 9 | 5. transfer : вывод монет с кошельков 10 | 6. 1inch_swap : свапы на 1inch 11 | 7. orbiter finance : bridge нативных токенов 12 | 8. woofi : свапы / бриджи 13 | 14 | ''' 15 | 16 | # ======================== 17 | MODULE = 1 # выбираем модуль от 1 до 8 18 | # ======================== 19 | 20 | IS_SLEEP = True # True / False. True если нужно поставить sleep между кошельками 21 | # от скольки до скольки спим между кошельками (секунды) : 22 | SLEEP_FROM = 100 23 | SLEEP_TO = 300 24 | 25 | # нужно ли рандомизировать (перемешивать) кошельки. True = да. False = нет 26 | RANDOM_WALLETS = False # True / False 27 | 28 | RETRY = 0 # кол-во попыток при ошибках / фейлах 29 | 30 | # настройка отправки результатов в тг бота 31 | TG_BOT_SEND = True # True / False. Если True, тогда будет отправлять результаты 32 | TG_TOKEN = '' # токен от тг-бота 33 | TG_ID = 0 # id твоего телеграмма 34 | 35 | # апи ключи от бирж. если биржей не пользуешься, можно не вставлять 36 | CEX_KEYS = { 37 | 'binance' : {'api_key': '', 'api_secret': ''}, 38 | 'mexc' : {'api_key': '', 'api_secret': ''}, 39 | 'kucoin' : {'api_key': '', 'api_secret': '', 'password': ''}, 40 | 'huobi' : {'api_key': '', 'api_secret': ''}, 41 | 'bybit' : {'api_key': '', 'api_secret': ''}, 42 | 'okx' : {'api_key': '', 'api_secret': '', 'password': ''}, 43 | } 44 | 45 | def value_web3_checker(): 46 | 47 | ''' 48 | чекер монет через web3, смотрит по 1 монете в конкретной сети 49 | ''' 50 | 51 | chain = 'arbitrum' # в какой сети смотрим 52 | address_contract = '' # адреса монеты. пусто если нативная монета. 53 | min_balance = 0 # по дефолту = 0. если баланс < этого числа, кошелек будет помечен 54 | 55 | file_name = 'web3_balances' # имя файла в который будем сохранять данные. создается сам 56 | 57 | return chain, address_contract, min_balance, file_name 58 | 59 | def value_debank(): 60 | 61 | ''' 62 | чекер баланса через debank, смотрит все сети, протоколы и нфт 63 | ''' 64 | 65 | # какие модули включены. если какой-то модуль не нужен, закомментируй (#) его. модуль nft самый долгий, по ненадобности лучше его отключать 66 | modules = [ 67 | 'token', # смотрит монеты 68 | 'nft', # смотрит нфт 69 | 'protocol' # смотрит протоколы 70 | ] 71 | 72 | # в каких сетях смотрим нфт. если какая-то сеть не нужна, закомментируй (#) ее 73 | nft_chains = [ 74 | 'op', 75 | 'eth', 76 | # 'arb', 77 | # 'matic', 78 | # 'bsc' 79 | ] 80 | 81 | check_min_value = 5 # $. если баланс монеты / протокола будет меньше этого числа, монета / протокол не будут записаны в файл 82 | check_chain = 'ARB' # в какой сети ищем монету (отдельно выделит ее баланс) 83 | check_coin = 'ETH' # какую монету ищем (отдельно выделит ее баланс) 84 | 85 | 86 | file_name = 'debank' # имя файла в который будем сохранять данные. создается сам 87 | 88 | return file_name, check_min_value, check_chain, check_coin, modules, nft_chains 89 | 90 | def value_exchange(): 91 | 92 | ''' 93 | вывод монет с биржи 94 | биржи : binance | bybit | kucoin | mexc | huobi 95 | ''' 96 | 97 | exchange = 'binance' # запиши сюда биржу 98 | 99 | chain = 'BEP20' # в какой сети выводим 100 | symbol = 'USDT' # какой токен выводим 101 | 102 | amount_from = 13 # от какого кол-ва монет выводим 103 | amount_to = 20 # до какого кол-ва монет выводим 104 | 105 | 106 | return exchange, chain, symbol, amount_from, amount_to 107 | 108 | def value_okx(): 109 | 110 | ''' 111 | выводит только с funding, есть вывод с суб-аккаунтов 112 | ''' 113 | 114 | chain = 'Arbitrum one' # с какой сети выводить 115 | symbol = 'ETH' # какую монету выводить 116 | 117 | amount_from = 0.1 # выводим от 118 | amount_to = 0.2 # выводим до 119 | 120 | FEE = 0.0001 # комиссия на вывод 121 | SUB_ACC = True # True / False. True если нужно выводить с суб-аккаунтов 122 | 123 | API_KEY = CEX_KEYS['okx']['api_key'] 124 | API_SECRET = CEX_KEYS['okx']['api_secret'] 125 | PASSWORD = CEX_KEYS['okx']['password'] 126 | 127 | return chain, symbol, amount_from, amount_to, API_KEY, API_SECRET, PASSWORD, FEE, SUB_ACC 128 | 129 | def value_transfer(): 130 | 131 | ''' 132 | вывод (трансфер) монет с кошельков 133 | chains : ethereum | optimism | bsc | polygon | arbitrum | avalanche | fantom | nova | zksync 134 | ''' 135 | 136 | chain = 'arbitrum' # в какой сети выводить 137 | token_address = '' # пусто если нативный токен сети 138 | 139 | amount_from = 1 # от какого кол-ва монет делаем трансфер 140 | amount_to = 2 # до какого кол-ва монет делаем трансфер 141 | 142 | transfer_all_balance = False # True / False. если True, тогда выводим весь баланс 143 | min_amount_transfer = 0 # если баланс будет меньше этого числа, выводить не будет 144 | keep_value_from = 0 # от скольки монет оставляем на кошельке (работает только при : transfer_all_balance = True) 145 | keep_value_to = 0 # до скольки монет оставляем на кошельке (работает только при : transfer_all_balance = True) 146 | 147 | return chain, amount_from, amount_to, transfer_all_balance, min_amount_transfer, keep_value_from, keep_value_to, token_address 148 | 149 | def value_1inch_swap(): 150 | 151 | ''' 152 | свапы на 1inch 153 | chains : ethereum | optimism | bsc | polygon | arbitrum | avalanche | fantom | nova | zksync 154 | ''' 155 | 156 | chain = 'zksync' # в какой сети свапаем 157 | from_token_address = '' # пусто если нативный токен сети 158 | to_token_address = '0x3355df6d4c9c3035724fd0e3914de96a5a83aaf4' # пусто если нативный токен сети 159 | 160 | amount_from = 0.0001 # от какого кол-ва монет свапаем 161 | amount_to = 0.0002 # до какого кол-ва монет свапаем 162 | 163 | swap_all_balance = False # True / False. если True, тогда свапаем весь баланс 164 | min_amount_swap = 0 # если баланс будет меньше этого числа, свапать не будет 165 | keep_value_from = 0 # от скольки монет оставляем на кошельке (работает только при : swap_all_balance = True) 166 | keep_value_to = 0 # до скольки монет оставляем на кошельке (работает только при : swap_all_balance = True) 167 | 168 | slippage = 3 # слиппейдж, дефолт от 1 до 3 169 | 170 | divider_zksync = 3 # на сколько делим gasLimit в zksync : советую ставить 3-4. исполняется только на zksync 171 | 172 | return chain, swap_all_balance, min_amount_swap, keep_value_from, keep_value_to, amount_from, amount_to, from_token_address, to_token_address, slippage, divider_zksync 173 | 174 | def value_orbiter(): 175 | 176 | ''' 177 | бридж нативных токенов через https://www.orbiter.finance/ 178 | chains : zksync | polygon | ethereum | bsc | arbitrum | optimism | fantom | polygon_zkevm | nova 179 | 180 | минимальный бридж : 0.011001 181 | ''' 182 | 183 | from_chain = 'arbitrum' # с какой сети 184 | to_chain = 'zksync' # в какую сеть 185 | 186 | amount_from = 0.015 # от какого кол-ва монет делаем бридж 187 | amount_to = 0.02 # до какого кол-ва монет делаем бридж 188 | 189 | bridge_all_balance = False # True / False. если True, тогда бриджим весь баланс 190 | min_amount_bridge = 0.01 # если баланс будет меньше этого числа, выводить не будет 191 | keep_value_from = 0 # от скольки монет оставляем на кошельке (работает только при : bridge_all_balance = True) 192 | keep_value_to = 0 # до скольки монет оставляем на кошельке (работает только при : bridge_all_balance = True) 193 | 194 | return from_chain, to_chain, bridge_all_balance, amount_from, amount_to, min_amount_bridge, keep_value_from, keep_value_to 195 | 196 | def value_woofi(): 197 | 198 | ''' 199 | свап / бридж на https://fi.woo.org/ (бриджи идут через layerzero) 200 | chains : avalanche | polygon | ethereum | bsc | arbitrum | optimism | fantom 201 | ''' 202 | 203 | from_chain = 'arbitrum' 204 | to_chain = 'bsc' 205 | 206 | from_token = '' # пусто если нативный токен сети 207 | to_token = '' # пусто если нативный токен сети 208 | 209 | amount_from = 2 # от какого кол-ва from_token свапаем 210 | amount_to = 3 # до какого кол-ва from_token свапаем 211 | 212 | swap_all_balance = False # True / False. если True, тогда свапаем весь баланс 213 | min_amount_swap = 0 # если баланс будет меньше этого числа, свапать не будет 214 | keep_value_from = 0 # от скольки монет оставляем на кошельке (работает только при : swap_all_balance = True) 215 | keep_value_to = 0 # до скольки монет оставляем на кошельке (работает только при : swap_all_balance = True) 216 | 217 | 218 | return from_chain, to_chain, from_token, to_token, swap_all_balance, amount_from, amount_to, min_amount_swap, keep_value_from, keep_value_to 219 | 220 | -------------------------------------------------------------------------------- /debank.py: -------------------------------------------------------------------------------- 1 | 2 | from config import * 3 | 4 | get_result = { 5 | 'token' : {}, 6 | 'nft' : { 7 | 'op' : {}, 8 | 'eth' : {}, 9 | 'arb' : {}, 10 | 'matic' : {}, 11 | 'bsc' : {}, 12 | }, 13 | 'protocol' : {} 14 | } 15 | 16 | def evm_wallet(key): 17 | 18 | try: 19 | web3 = Web3(Web3.HTTPProvider(DATA['ethereum']['rpc'])) 20 | wallet = web3.eth.account.from_key(key).address 21 | return wallet 22 | except: 23 | return key 24 | 25 | async def get_debank(session, address, type_, chain=''): 26 | 27 | while True: 28 | 29 | try: 30 | 31 | sleep = 3 32 | 33 | urls = { 34 | 'token' : f'https://api.debank.com/token/cache_balance_list?user_addr={address}', 35 | 'nft' : f'https://api.debank.com/nft/collection_list?user_addr={address}&chain={chain}', 36 | 'protocol' : f'https://api.debank.com/portfolio/project_list?user_addr={address}', 37 | } 38 | 39 | proxy = PROXIES[random.randint(0,len(PROXIES)-1)] 40 | 41 | async with session.get(urls[type_], proxy=proxy, timeout=10) as resp: 42 | 43 | if resp.status == 200: 44 | resp_json = await resp.json(content_type=None) 45 | if type_ == 'nft': 46 | 47 | if resp_json['data']['job']: 48 | await asyncio.sleep(sleep) 49 | else: 50 | 51 | get_result[type_][chain].update({address : resp_json}) 52 | logger.success(f'{address} | {type_} : {chain}') 53 | break 54 | 55 | else: 56 | get_result[type_].update({address : resp_json}) 57 | logger.success(f'{address} | {type_}') 58 | break 59 | else: 60 | # logger.info(f'resp.status = {resp.status}, try again in {sleep} sec.') 61 | await asyncio.sleep(sleep) 62 | 63 | except Exception as error: 64 | logger.info(f'{address} | {type_} : {error}') 65 | await asyncio.sleep(3) 66 | 67 | async def checker_main(modules, nft_chains, wallets): 68 | 69 | async with aiohttp.ClientSession() as session: 70 | tasks = [] 71 | 72 | for address in wallets: 73 | 74 | 75 | if 'token' in modules: 76 | 77 | task = asyncio.create_task(get_debank(session, address, 'token')) 78 | tasks.append(task) 79 | 80 | 81 | if 'protocol' in modules: 82 | 83 | task = asyncio.create_task(get_debank(session, address, 'protocol')) 84 | tasks.append(task) 85 | 86 | 87 | if 'nft' in modules: 88 | 89 | for chain in nft_chains: 90 | 91 | task = asyncio.create_task(get_debank(session, address, 'nft', chain)) 92 | tasks.append(task) 93 | 94 | 95 | await asyncio.gather(*tasks) 96 | 97 | def get_json_data(check_min_value, wallets): 98 | 99 | total_result = {} 100 | 101 | for wallet in wallets: 102 | total_result.update({wallet : { 103 | 'token' : [], 104 | 'nft' : [], 105 | 'protocol' : [], 106 | 'protocol_value' : 0, 107 | 'token_value' : 0, 108 | 'total_value' : 0, 109 | }}) 110 | 111 | 112 | # check tokens 113 | for tokens in get_result['token'].items(): 114 | 115 | wallet = tokens[0] 116 | data = tokens[1] 117 | 118 | for items in data['data']: 119 | 120 | chain = items['chain'].upper() 121 | price = items['price'] 122 | amount = items['amount'] 123 | symbol = items['optimized_symbol'] 124 | value = amount * price 125 | 126 | if value > check_min_value: 127 | 128 | total_result[wallet]['token'].append( 129 | { 130 | 'chain' : chain, 131 | 'symbol' : symbol, 132 | 'amount' : amount, 133 | 'value' : value, 134 | } 135 | ) 136 | 137 | total_result[wallet]['token_value'] += value 138 | 139 | # check nfts 140 | for nfts in get_result['nft'].items(): 141 | 142 | chain = nfts[0].upper() 143 | data_ = nfts[1] 144 | 145 | for w_ in data_.items(): 146 | 147 | wallet = w_[0] 148 | data = w_[1] 149 | 150 | for items in data['data']['result']['data']: 151 | 152 | amount = items['amount'] 153 | name = items['name'] 154 | 155 | total_result[wallet]['nft'].append( 156 | { 157 | 'chain' : chain, 158 | 'name' : name, 159 | 'amount' : amount, 160 | } 161 | ) 162 | 163 | # check protocols 164 | for tokens in get_result['protocol'].items(): 165 | 166 | wallet = tokens[0] 167 | data = tokens[1] 168 | 169 | for items in data['data']: 170 | 171 | chain = items['chain'].upper() 172 | name = items['name'] 173 | value = int(items['portfolio_item_list'][0]['stats']['asset_usd_value']) 174 | 175 | if value > check_min_value: 176 | 177 | total_result[wallet]['protocol'].append( 178 | { 179 | 'chain' : chain, 180 | 'name' : name, 181 | 'value' : value, 182 | } 183 | ) 184 | 185 | total_result[wallet]['protocol_value'] += value 186 | 187 | # check total value 188 | for wallet in wallets: 189 | total_result[wallet]['total_value'] = total_result[wallet]['protocol_value'] + total_result[wallet]['token_value'] 190 | 191 | # call_json(total_result, 'test2') 192 | 193 | return total_result 194 | 195 | def round_to(num, digits=3): 196 | try: 197 | if num == 0: return 0 198 | scale = int(-math.floor(math.log10(abs(num - int(num))))) + digits - 1 199 | if scale < digits: scale = digits 200 | return round(num, scale) 201 | except: return num 202 | 203 | def send_result(get_json, file_name, check_chain, check_coin): 204 | 205 | 206 | file = open(f'{outfile}results/{file_name}.txt', 'w', encoding='utf-8') 207 | 208 | with open(f'{outfile}results/{file_name}.csv', 'w', newline='') as csvfile: 209 | spamwriter = csv.writer(csvfile, delimiter=',', quoting=csv.QUOTE_MINIMAL) 210 | 211 | spamwriter.writerow(['№', 'wallet', 'balance $', 'protocols $', 'tokens $', 'nft amount']) 212 | 213 | all_wallets_value = [] 214 | all_finder_token = [] 215 | 216 | zero = 0 217 | for wallets in get_json.items(): 218 | zero+= 1 219 | 220 | wallet = wallets[0] 221 | data = wallets[1] 222 | 223 | file.write(f'\n{zero}. {wallet}\n') 224 | 225 | tokens = [] 226 | for items in data['token']: 227 | 228 | chain = items['chain'] 229 | symbol = items['symbol'] 230 | amount = round_to(items['amount']) 231 | value = int(items['value']) 232 | 233 | tokens.append([chain, amount, symbol, f'{value} $']) 234 | 235 | if check_chain != '': 236 | if check_chain == chain: 237 | if check_coin == symbol: 238 | finder = amount 239 | else: 240 | if check_coin == symbol: 241 | finder = amount 242 | 243 | protocols = [] 244 | for items in data['protocol']: 245 | 246 | chain = items['chain'] 247 | name = items['name'] 248 | value = int(items['value']) 249 | 250 | protocols.append([chain, name, f'{value} $']) 251 | 252 | nfts = [] 253 | nft_amounts = [] 254 | for items in data['nft']: 255 | 256 | chain = items['chain'] 257 | name = items['name'] 258 | amount = int(items['amount']) 259 | 260 | nft_amounts.append(amount) 261 | nfts.append([chain, name, amount]) 262 | 263 | protocol_value = int(data['protocol_value']) 264 | token_value = int(data['token_value']) 265 | total_value = int(data['total_value']) 266 | 267 | table_type = 'double_outline' 268 | 269 | head_table = ['chain', 'amount', 'symbol', 'value'] 270 | tokens_ = tabulate(tokens, head_table, tablefmt=table_type) 271 | 272 | head_table = ['chain', 'name', 'value'] 273 | protocols_ = tabulate(protocols, head_table, tablefmt=table_type) 274 | 275 | head_table = ['chain', 'name', 'amount'] 276 | nfts_ = tabulate(nfts, head_table, tablefmt=table_type) 277 | 278 | cprint(f'\n{zero}. {wallet}\n', 'yellow') 279 | 280 | if len(tokens) > 0: 281 | file.write(f'\n{tokens_}\n') 282 | cprint(tokens_, 'white') 283 | 284 | if len(protocols) > 0: 285 | file.write(f'\n{protocols_}\n') 286 | cprint(protocols_, 'white') 287 | 288 | if len(nfts) > 0: 289 | file.write(f'\n{nfts_}\n') 290 | cprint(nfts_, 'white') 291 | 292 | file.write(f'\ntotal_value : {total_value} $\n') 293 | cprint(f'\ntotal_value : {total_value} $\n', 'green') 294 | 295 | 296 | if check_coin != '': 297 | file.write(f'{check_coin} : {finder}\n') 298 | cprint(f'{check_coin} : {finder}\n', 'green') 299 | all_finder_token.append(finder) 300 | 301 | spamwriter.writerow([zero, wallet, total_value, protocol_value, token_value, sum(nft_amounts)]) 302 | 303 | all_wallets_value.append(total_value) 304 | 305 | cprint(f'\n>>> ALL WALLETS VALUE : {sum(all_wallets_value)} $ <<<\n', 'blue') 306 | file.write(f'\n>>> ALL WALLETS VALUE : {sum(all_wallets_value)} $ <<<\n') 307 | spamwriter.writerow(['ALL_VALUE :', sum(all_wallets_value)]) 308 | 309 | amount_finder_coin = round_to(sum(all_finder_token)) 310 | if amount_finder_coin > 0: 311 | cprint(f'\n>>> {check_coin} : {amount_finder_coin} $ <<<\n', 'blue') 312 | file.write(f'\n>>> {check_coin} : {amount_finder_coin} $ <<<\n') 313 | spamwriter.writerow([f'{check_coin}', amount_finder_coin]) 314 | 315 | file.close() 316 | 317 | cprint(f'результаты записаны в файлы : {outfile}{file_name}.csv и {outfile}{file_name}.txt\n', 'blue') 318 | 319 | 320 | def start_debank(): 321 | 322 | wallets = [] 323 | for key in WALLETS: 324 | wallet = evm_wallet(key) 325 | wallets.append(wallet) 326 | 327 | file_name, check_min_value, check_chain, check_coin, modules, nft_chains = value_debank() 328 | 329 | loop = asyncio.get_event_loop() 330 | loop.run_until_complete(checker_main(modules, nft_chains, wallets)) 331 | 332 | get_json = get_json_data(check_min_value, wallets) 333 | send_result(get_json, file_name, check_chain, check_coin) 334 | 335 | 336 | 337 | -------------------------------------------------------------------------------- /data/abi/abi.py: -------------------------------------------------------------------------------- 1 | ABI_WOOFI_BRIDGE = '[{"inputs":[{"internalType":"address","name":"_weth","type":"address"},{"internalType":"address","name":"_wooRouter","type":"address"},{"internalType":"address","name":"_stargateRouter","type":"address"},{"internalType":"uint16","name":"_sgChainIdLocal","type":"uint16"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"refId","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"bridgedToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"bridgedAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"toToken","type":"address"},{"indexed":false,"internalType":"address","name":"realToToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"minToAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"realToAmount","type":"uint256"}],"name":"WooCrossSwapOnDstChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"refId","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"fromToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"fromAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minBridgeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"realBridgeAmount","type":"uint256"}],"name":"WooCrossSwapOnSrcChain","type":"event"},{"inputs":[],"name":"ETH_PLACEHOLDER_ADDR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"addDirectBridgeToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"allDirectBridgeTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allDirectBridgeTokensLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bridgeSlippage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"refId","type":"uint256"},{"internalType":"address payable","name":"to","type":"address"},{"components":[{"internalType":"address","name":"fromToken","type":"address"},{"internalType":"address","name":"bridgeToken","type":"address"},{"internalType":"uint256","name":"fromAmount","type":"uint256"},{"internalType":"uint256","name":"minBridgeAmount","type":"uint256"}],"internalType":"struct IWooCrossChainRouterV2.SrcInfos","name":"srcInfos","type":"tuple"},{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"address","name":"toToken","type":"address"},{"internalType":"address","name":"bridgeToken","type":"address"},{"internalType":"uint256","name":"minToAmount","type":"uint256"},{"internalType":"uint256","name":"airdropNativeAmount","type":"uint256"}],"internalType":"struct IWooCrossChainRouterV2.DstInfos","name":"dstInfos","type":"tuple"}],"name":"crossSwap","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"dstGasForNoSwapCall","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dstGasForSwapCall","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stuckToken","type":"address"}],"name":"inCaseTokenGotStuck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcChainId","type":"uint16"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"bytes32","name":"from","type":"bytes32"},{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"onOFTReceived","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"refId","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"components":[{"internalType":"address","name":"fromToken","type":"address"},{"internalType":"address","name":"bridgeToken","type":"address"},{"internalType":"uint256","name":"fromAmount","type":"uint256"},{"internalType":"uint256","name":"minBridgeAmount","type":"uint256"}],"internalType":"struct IWooCrossChainRouterV2.SrcInfos","name":"srcInfos","type":"tuple"},{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"address","name":"toToken","type":"address"},{"internalType":"address","name":"bridgeToken","type":"address"},{"internalType":"uint256","name":"minToAmount","type":"uint256"},{"internalType":"uint256","name":"airdropNativeAmount","type":"uint256"}],"internalType":"struct IWooCrossChainRouterV2.DstInfos","name":"dstInfos","type":"tuple"}],"name":"quoteLayerZeroFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"removeDirectBridgeToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bridgeSlippage","type":"uint256"}],"name":"setBridgeSlippage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_dstGasForNoSwapCall","type":"uint256"}],"name":"setDstGasForNoSwapCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_dstGasForSwapCall","type":"uint256"}],"name":"setDstGasForSwapCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_sgChainIdLocal","type":"uint16"}],"name":"setSgChainIdLocal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"address","name":"token","type":"address"}],"name":"setSgETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"poolId","type":"uint256"}],"name":"setSgPoolId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stargateRouter","type":"address"}],"name":"setStargateRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"oft","type":"address"}],"name":"setTokenToOFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"address","name":"wooCrossChainRouter","type":"address"}],"name":"setWooCrossChainRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wooRouter","type":"address"}],"name":"setWooRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sgChainIdLocal","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"sgETHs","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"address","name":"","type":"address"}],"name":"sgPoolIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"bridgedToken","type":"address"},{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"sgReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stargateRouter","outputs":[{"internalType":"contract IStargateRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokenToOFTs","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"wooCrossChainRouters","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wooRouter","outputs":[{"internalType":"contract IWooRouterV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]' 2 | 3 | ABI_WOOFI_SWAP = '[{"inputs":[{"internalType":"address","name":"_weth","type":"address"},{"internalType":"address","name":"_pool","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newPool","type":"address"}],"name":"WooPoolChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum IWooRouterV2.SwapType","name":"swapType","type":"uint8"},{"indexed":true,"internalType":"address","name":"fromToken","type":"address"},{"indexed":true,"internalType":"address","name":"toToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"fromAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"rebateTo","type":"address"}],"name":"WooRouterSwap","type":"event"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"approveTarget","type":"address"},{"internalType":"address","name":"swapTarget","type":"address"},{"internalType":"address","name":"fromToken","type":"address"},{"internalType":"address","name":"toToken","type":"address"},{"internalType":"uint256","name":"fromAmount","type":"uint256"},{"internalType":"uint256","name":"minToAmount","type":"uint256"},{"internalType":"address payable","name":"to","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"externalSwap","outputs":[{"internalType":"uint256","name":"realToAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"stuckToken","type":"address"}],"name":"inCaseTokenGotStuck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"fromToken","type":"address"},{"internalType":"address","name":"toToken","type":"address"},{"internalType":"uint256","name":"fromAmount","type":"uint256"}],"name":"querySwap","outputs":[{"internalType":"uint256","name":"toAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quoteToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPool","type":"address"}],"name":"setPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"whitelisted","type":"bool"}],"name":"setWhitelisted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"fromToken","type":"address"},{"internalType":"address","name":"toToken","type":"address"},{"internalType":"uint256","name":"fromAmount","type":"uint256"},{"internalType":"uint256","name":"minToAmount","type":"uint256"},{"internalType":"address payable","name":"to","type":"address"},{"internalType":"address","name":"rebateTo","type":"address"}],"name":"swap","outputs":[{"internalType":"uint256","name":"realToAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"fromToken","type":"address"},{"internalType":"address","name":"toToken","type":"address"},{"internalType":"uint256","name":"fromAmount","type":"uint256"}],"name":"tryQuerySwap","outputs":[{"internalType":"uint256","name":"toAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wooPool","outputs":[{"internalType":"contract IWooPPV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]' 4 | 5 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | from config import * 2 | 3 | list_send = [] 4 | def send_msg(): 5 | 6 | try: 7 | 8 | str_send = '\n'.join(list_send) 9 | bot = telebot.TeleBot(TG_TOKEN) 10 | bot.send_message(TG_ID, str_send, parse_mode='html') 11 | 12 | except Exception as error: 13 | logger.error(error) 14 | 15 | # ============ web3_helpers ============ 16 | 17 | def evm_wallet(key): 18 | 19 | try: 20 | web3 = Web3(Web3.HTTPProvider(DATA['ethereum']['rpc'])) 21 | wallet = web3.eth.account.from_key(key).address 22 | return wallet 23 | except: 24 | return key 25 | 26 | def sign_tx(web3, contract_txn, privatekey): 27 | 28 | signed_tx = web3.eth.account.sign_transaction(contract_txn, privatekey) 29 | raw_tx_hash = web3.eth.send_raw_transaction(signed_tx.rawTransaction) 30 | tx_hash = web3.to_hex(raw_tx_hash) 31 | 32 | return tx_hash 33 | 34 | def check_data_token(web3, token_address): 35 | 36 | try: 37 | 38 | token_contract = web3.eth.contract(address=Web3.to_checksum_address(token_address), abi=ERC20_ABI) 39 | decimals = token_contract.functions.decimals().call() 40 | symbol = token_contract.functions.symbol().call() 41 | 42 | return token_contract, decimals, symbol 43 | 44 | except Exception as error: 45 | logger.error(error) 46 | 47 | def check_status_tx(chain, tx_hash): 48 | 49 | logger.info(f'{chain} : checking tx_status : {tx_hash}') 50 | 51 | while True: 52 | try: 53 | rpc_chain = DATA[chain]['rpc'] 54 | web3 = Web3(Web3.HTTPProvider(rpc_chain)) 55 | status_ = web3.eth.get_transaction_receipt(tx_hash) 56 | status = status_["status"] 57 | if status in [0, 1]: 58 | return status 59 | time.sleep(1) 60 | except Exception as error: 61 | # logger.info(f'error, try again : {error}') 62 | time.sleep(1) 63 | 64 | def add_gas_limit(web3, contract_txn): 65 | 66 | try: 67 | pluser = [1.3, 1.7] 68 | gasLimit = web3.eth.estimate_gas(contract_txn) 69 | contract_txn['gas'] = int(gasLimit * random.uniform(pluser[0], pluser[1])) 70 | # logger.info(f"gasLimit : {contract_txn['gas']}") 71 | except Exception as error: 72 | contract_txn['gas'] = random.randint(2000000, 3000000) 73 | logger.info(f"estimate_gas error : {error}. random gasLimit : {contract_txn['gas']}") 74 | 75 | return contract_txn 76 | 77 | def add_gas_price(web3, contract_txn): 78 | 79 | try: 80 | gas_price = web3.eth.gas_price 81 | contract_txn['gasPrice'] = int(gas_price * random.uniform(1.2, 1.3)) 82 | except Exception as error: 83 | logger.error(error) 84 | 85 | return contract_txn 86 | 87 | def round_to(num, digits=3): 88 | try: 89 | if num == 0: return 0 90 | scale = int(-math.floor(math.log10(abs(num - int(num))))) + digits - 1 91 | if scale < digits: scale = digits 92 | return round(num, scale) 93 | except: return num 94 | 95 | def check_balance(privatekey, chain, address_contract): 96 | try: 97 | 98 | rpc_chain = DATA[chain]['rpc'] 99 | web3 = Web3(Web3.HTTPProvider(rpc_chain)) 100 | 101 | try : wallet = web3.eth.account.from_key(privatekey).address 102 | except : wallet = privatekey 103 | 104 | if address_contract == '': # eth 105 | balance = web3.eth.get_balance(web3.to_checksum_address(wallet)) 106 | token_decimal = 18 107 | else: 108 | token_contract, token_decimal, symbol = check_data_token(web3, address_contract) 109 | balance = token_contract.functions.balanceOf(web3.to_checksum_address(wallet)).call() 110 | 111 | human_readable = decimalToInt(balance, token_decimal) 112 | 113 | # cprint(human_readable, 'blue') 114 | 115 | return human_readable 116 | 117 | except Exception as error: 118 | logger.error(error) 119 | time.sleep(1) 120 | check_balance(privatekey, chain, address_contract) 121 | 122 | def check_allowance(chain, token_address, wallet, spender): 123 | 124 | try: 125 | web3 = Web3(Web3.HTTPProvider(DATA[chain]['rpc'])) 126 | contract = web3.eth.contract(address=Web3.to_checksum_address(token_address), abi=ERC20_ABI) 127 | amount_approved = contract.functions.allowance(wallet, spender).call() 128 | return amount_approved 129 | except Exception as error: 130 | logger.error(error) 131 | 132 | # ============== modules ============== 133 | 134 | def approve_(privatekey, chain, token_address, spender, retry=0): 135 | 136 | try: 137 | 138 | web3 = Web3(Web3.HTTPProvider(DATA[chain]['rpc'])) 139 | # web3.middleware_onion.inject(geth_poa_middleware, layer=0) 140 | 141 | wallet = web3.eth.account.from_key(privatekey).address 142 | contract, decimals, symbol = check_data_token(web3, token_address) 143 | 144 | module_str = f'approve : {symbol}' 145 | 146 | contract_txn = contract.functions.approve( 147 | spender, 148 | 115792089237316195423570985008687907853269984665640564039457584007913129639935 149 | ).build_transaction( 150 | { 151 | "chainId": web3.eth.chain_id, 152 | "from": wallet, 153 | "nonce": web3.eth.get_transaction_count(wallet), 154 | 'gasPrice': 0, 155 | 'gas': 0, 156 | "value": 0 157 | } 158 | ) 159 | 160 | contract_txn = add_gas_price(web3, contract_txn) 161 | contract_txn = add_gas_limit(web3, contract_txn) 162 | 163 | tx_hash = sign_tx(web3, contract_txn, privatekey) 164 | tx_link = f'{DATA[chain]["scan"]}/{tx_hash}' 165 | 166 | status = check_status_tx(chain, tx_hash) 167 | 168 | if status == 1: 169 | logger.success(f"{module_str} | {tx_link}") 170 | else: 171 | logger.error(f"{module_str} | tx is failed | {tx_link}") 172 | if retry < RETRY: 173 | logger.info(f"try again in 10 sec.") 174 | sleeping(10, 10) 175 | approve_(privatekey, chain, token_address, spender, retry+1) 176 | 177 | except Exception as error: 178 | logger.error(f'{error}') 179 | if retry < RETRY: 180 | logger.info(f'try again in 10 sec.') 181 | sleeping(10, 10) 182 | approve_(privatekey, chain, token_address, spender, retry+1) 183 | 184 | def transfer(privatekey, retry=0): 185 | 186 | try: 187 | 188 | to_address = RECIPIENTS_WALLETS[privatekey] 189 | chain, amount_from, amount_to, transfer_all_balance, min_amount_transfer, keep_value_from, keep_value_to, token_address = value_transfer() 190 | 191 | keep_value = round(random.uniform(keep_value_from, keep_value_to), 8) 192 | 193 | module_str = f'transfer => {to_address}' 194 | 195 | web3 = Web3(Web3.HTTPProvider(DATA[chain]['rpc'])) 196 | 197 | account = web3.eth.account.from_key(privatekey) 198 | wallet = account.address 199 | nonce = web3.eth.get_transaction_count(wallet) 200 | 201 | if token_address == '': 202 | decimals = 18 203 | symbol = DATA[chain]['token'] 204 | else: 205 | token_contract, decimals, symbol = check_data_token(web3, token_address) 206 | 207 | if transfer_all_balance == True: amount = check_balance(privatekey, chain, token_address) - keep_value 208 | else: amount = round(random.uniform(amount_from, amount_to), 8) 209 | 210 | value = intToDecimal(amount, decimals) 211 | 212 | if amount >= min_amount_transfer: 213 | 214 | if token_address == '': 215 | 216 | contract_txn = { 217 | 'chainId': web3.eth.chain_id, 218 | 'gasPrice': 0, 219 | 'nonce': nonce, 220 | 'gas': 0, 221 | 'to': Web3.to_checksum_address(to_address), 222 | 'value': int(value) 223 | } 224 | 225 | else: 226 | 227 | tx = { 228 | 'chainId': web3.eth.chain_id, 229 | 'gasPrice': 0, 230 | 'gas': 0, 231 | 'nonce': nonce, 232 | } 233 | 234 | contract_txn = token_contract.functions.transfer( 235 | Web3.to_checksum_address(to_address), 236 | int(value) 237 | ).build_transaction(tx) 238 | 239 | contract_txn = add_gas_price(web3, contract_txn) 240 | contract_txn = add_gas_limit(web3, contract_txn) 241 | 242 | if token_address == '': 243 | if transfer_all_balance == True: 244 | gas_price = contract_txn['gasPrice'] 245 | gas_limit = contract_txn['gas'] 246 | gas_gas = gas_price * gas_limit 247 | contract_txn['value'] = int(value) - int(gas_gas) 248 | 249 | tx_hash = sign_tx(web3, contract_txn, privatekey) 250 | tx_link = f'{DATA[chain]["scan"]}/{tx_hash}' 251 | 252 | module_str = f'transfer {round_to(amount)} {symbol} => {to_address}' 253 | 254 | status = check_status_tx(chain, tx_hash) 255 | if status == 1: 256 | logger.success(f'{module_str} | {tx_link}') 257 | list_send.append(f'{STR_DONE}{module_str}') 258 | else: 259 | if retry < RETRY: 260 | logger.info(f'{module_str} | tx is failed, try again in 10 sec | {tx_link}') 261 | sleeping(10, 10) 262 | transfer(privatekey, retry+1) 263 | else: 264 | logger.error(f'{module_str} | tx is failed | {tx_link}') 265 | 266 | else: 267 | logger.error(f"{module_str} : can't transfer : {amount} (amount) < {min_amount_transfer} (min_amount_transfer)") 268 | list_send.append(f'{STR_CANCEL}{module_str} : {amount} < {min_amount_transfer}') 269 | 270 | except Exception as error: 271 | 272 | logger.error(f'{module_str} | {error}') 273 | if retry < RETRY: 274 | logger.info(f'try again | {wallet}') 275 | sleeping(10, 10) 276 | transfer(privatekey, retry+1) 277 | else: 278 | list_send.append(f'{STR_CANCEL}{module_str}') 279 | 280 | def get_api_call_data(url): 281 | try: 282 | call_data = requests.get(url) 283 | except Exception as e: 284 | print(e) 285 | return get_api_call_data(url) 286 | try: 287 | api_data = call_data.json() 288 | return api_data 289 | except Exception as e: 290 | print(call_data.text) 291 | 292 | def inch_swap(privatekey, retry=0): 293 | 294 | try: 295 | 296 | inch_version = 5 297 | 298 | chain, swap_all_balance, min_amount_swap, keep_value_from, keep_value_to, amount_from, amount_to, from_token_address, to_token_address, slippage, divider = value_1inch_swap() 299 | 300 | keep_value = round(random.uniform(keep_value_from, keep_value_to), 8) 301 | 302 | if chain == 'zksync': divider = divider 303 | else: divider = 1 304 | 305 | web3 = Web3(Web3.HTTPProvider(DATA[chain]['rpc'])) 306 | chain_id = web3.eth.chain_id 307 | 308 | if from_token_address == '': 309 | from_token_address = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' 310 | from_decimals = 18 311 | from_symbol = DATA[chain]['token'] 312 | else: 313 | from_token_contract, from_decimals, from_symbol = check_data_token(web3, from_token_address) 314 | 315 | if to_token_address == '': 316 | to_token_address = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' 317 | to_symbol = DATA[chain]['token'] 318 | else: 319 | to_token_contract, to_decimals, to_symbol = check_data_token(web3, to_token_address) 320 | 321 | account = web3.eth.account.from_key(privatekey) 322 | wallet = account.address 323 | 324 | if swap_all_balance == True: amount = check_balance(privatekey, chain, from_token_address) - keep_value 325 | else: amount = round(random.uniform(amount_from, amount_to), 8) 326 | 327 | amount = amount*0.999 328 | amount_to_swap = intToDecimal(amount, from_decimals) 329 | 330 | spender_json = get_api_call_data(f'https://api.1inch.io/v{inch_version}.0/{chain_id}/approve/spender') 331 | spender = Web3.to_checksum_address(spender_json['address']) 332 | 333 | # если токен не нативный, тогда проверяем апрув и если он меньше нужного, делаем апруваем 334 | if from_token_address != '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE': 335 | allowance_amount = check_allowance(chain, from_token_address, wallet, spender) 336 | if amount_to_swap > allowance_amount: 337 | approve_(privatekey, chain, from_token_address, spender) 338 | sleeping(5, 5) 339 | 340 | _1inchurl = f'https://api.1inch.io/v{inch_version}.0/{chain_id}/swap?fromTokenAddress={from_token_address}&toTokenAddress={to_token_address}&amount={amount_to_swap}&fromAddress={wallet}&slippage={slippage}' 341 | json_data = get_api_call_data(_1inchurl) 342 | 343 | # cprint(json_data, 'yellow') 344 | 345 | tx = json_data['tx'] 346 | 347 | tx['chainId'] = chain_id 348 | tx['nonce'] = web3.eth.get_transaction_count(wallet) 349 | tx['to'] = Web3.to_checksum_address(tx['to']) 350 | tx['gasPrice'] = int(tx['gasPrice']) 351 | tx['gas'] = int(int(tx['gas']) / divider) 352 | tx['value'] = int(tx['value']) 353 | 354 | # cprint(tx, 'blue') 355 | 356 | if amount >= min_amount_swap: 357 | 358 | tx_hash = sign_tx(web3, tx, privatekey) 359 | tx_link = f'{DATA[chain]["scan"]}/{tx_hash}' 360 | 361 | module_str = f'1inch_swap : {round_to(amount)} {from_symbol} => {to_symbol}' 362 | 363 | status = check_status_tx(chain, tx_hash) 364 | 365 | if status == 1: 366 | logger.success(f'{module_str} | {tx_link}') 367 | list_send.append(f'{STR_DONE}{module_str}') 368 | else: 369 | logger.error(f'{module_str} | tx is failed | {tx_link}') 370 | if retry < RETRY: 371 | logger.info(f'try again in 10 sec.') 372 | sleeping(10, 10) 373 | inch_swap(privatekey, retry+1) 374 | 375 | else: 376 | logger.error(f"{module_str} : can't swap : {amount} (amount) < {min_amount_swap} (min_amount_swap)") 377 | list_send.append(f'{STR_CANCEL}{module_str} : {amount} < {min_amount_swap}') 378 | 379 | except KeyError: 380 | logger.error(json_data['description']) 381 | module_str = f'1inch_swap' 382 | list_send.append(f'{STR_CANCEL}{module_str}') 383 | 384 | except Exception as error: 385 | module_str = f'1inch_swap' 386 | logger.error(f'{module_str} | error : {error}') 387 | if retry < RETRY: 388 | logger.info(f'try again in 10 sec.') 389 | sleeping(10, 10) 390 | inch_swap(privatekey, retry+1) 391 | else: 392 | list_send.append(f'{STR_CANCEL}{module_str}') 393 | 394 | def okx_data(api_key, secret_key, passphras, request_path="/api/v5/account/balance?ccy=USDT", body='', meth="GET"): 395 | 396 | try: 397 | import datetime 398 | def signature( 399 | timestamp: str, method: str, request_path: str, secret_key: str, body: str = "" 400 | ) -> str: 401 | if not body: 402 | body = "" 403 | 404 | message = timestamp + method.upper() + request_path + body 405 | mac = hmac.new( 406 | bytes(secret_key, encoding="utf-8"), 407 | bytes(message, encoding="utf-8"), 408 | digestmod="sha256", 409 | ) 410 | d = mac.digest() 411 | return base64.b64encode(d).decode("utf-8") 412 | 413 | dt_now = datetime.datetime.utcnow() 414 | ms = str(dt_now.microsecond).zfill(6)[:3] 415 | timestamp = f"{dt_now:%Y-%m-%dT%H:%M:%S}.{ms}Z" 416 | 417 | base_url = "https://www.okex.com" 418 | headers = { 419 | "Content-Type": "application/json", 420 | "OK-ACCESS-KEY": api_key, 421 | "OK-ACCESS-SIGN": signature(timestamp, meth, request_path, secret_key, body), 422 | "OK-ACCESS-TIMESTAMP": timestamp, 423 | "OK-ACCESS-PASSPHRASE": passphras, 424 | 'x-simulated-trading': '0' 425 | } 426 | except Exception as ex: 427 | logger.error(ex) 428 | return base_url, request_path, headers 429 | 430 | def okx_withdraw(privatekey, retry=0): 431 | 432 | CHAIN, SYMBOL, amount_from, amount_to, api_key, secret_key, passphras, FEE, SUB_ACC = value_okx() 433 | AMOUNT = round(random.uniform(amount_from, amount_to), 7) 434 | 435 | wallet = evm_wallet(privatekey) 436 | 437 | try: 438 | 439 | if SUB_ACC == True: 440 | 441 | _, _, headers = okx_data(api_key, secret_key, passphras, request_path=f"/api/v5/users/subaccount/list", meth="GET") 442 | list_sub = requests.get("https://www.okx.cab/api/v5/users/subaccount/list", timeout=10, headers=headers) 443 | list_sub = list_sub.json() 444 | 445 | 446 | for sub_data in list_sub['data']: 447 | 448 | name_sub = sub_data['subAcct'] 449 | 450 | _, _, headers = okx_data(api_key, secret_key, passphras, request_path=f"/api/v5/asset/subaccount/balances?subAcct={name_sub}&ccy={SYMBOL}", meth="GET") 451 | sub_balance = requests.get(f"https://www.okx.cab/api/v5/asset/subaccount/balances?subAcct={name_sub}&ccy={SYMBOL}",timeout=10, headers=headers) 452 | sub_balance = sub_balance.json() 453 | sub_balance = sub_balance['data'][0]['bal'] 454 | 455 | logger.info(f'{name_sub} | sub_balance : {sub_balance}') 456 | 457 | body = {"ccy": f"{SYMBOL}", "amt": str(sub_balance), "from": 6, "to": 6, "type": "2", "subAcct": name_sub} 458 | _, _, headers = okx_data(api_key, secret_key, passphras, request_path=f"/api/v5/asset/transfer", body=str(body), meth="POST") 459 | a = requests.post("https://www.okx.cab/api/v5/asset/transfer",data=str(body), timeout=10, headers=headers) 460 | a = a.json() 461 | time.sleep(1) 462 | 463 | try: 464 | _, _, headers = okx_data(api_key, secret_key, passphras, request_path=f"/api/v5/account/balance?ccy={SYMBOL}") 465 | balance = requests.get(f'https://www.okx.cab/api/v5/account/balance?ccy={SYMBOL}', timeout=10, headers=headers) 466 | balance = balance.json() 467 | balance = balance["data"][0]["details"][0]["cashBal"] 468 | # print(balance) 469 | 470 | if balance != 0: 471 | body = {"ccy": f"{SYMBOL}", "amt": float(balance), "from": 18, "to": 6, "type": "0", "subAcct": "", "clientId": "", "loanTrans": "", "omitPosRisk": ""} 472 | _, _, headers = okx_data(api_key, secret_key, passphras, request_path=f"/api/v5/asset/transfer", body=str(body), meth="POST") 473 | a = requests.post("https://www.okx.cab/api/v5/asset/transfer",data=str(body), timeout=10, headers=headers) 474 | except Exception as ex: 475 | pass 476 | 477 | body = {"ccy":SYMBOL, "amt":AMOUNT, "fee":FEE, "dest":"4", "chain":f"{SYMBOL}-{CHAIN}", "toAddr":wallet} 478 | _, _, headers = okx_data(api_key, secret_key, passphras, request_path=f"/api/v5/asset/withdrawal", meth="POST", body=str(body)) 479 | a = requests.post("https://www.okx.cab/api/v5/asset/withdrawal",data=str(body), timeout=10, headers=headers) 480 | result = a.json() 481 | # cprint(result, 'blue') 482 | 483 | if result['code'] == '0': 484 | logger.success(f"withdraw success => {wallet} | {AMOUNT} {SYMBOL}") 485 | list_send.append(f'{STR_DONE}okx_withdraw') 486 | else: 487 | error = result['msg'] 488 | logger.error(f"withdraw unsuccess => {wallet} | error : {error}") 489 | list_send.append(f"{STR_CANCEL}okx_withdraw : {result['msg']}") 490 | 491 | except Exception as error: 492 | logger.error(f"withdraw unsuccess => {wallet} | error : {error}") 493 | if retry < RETRY: 494 | logger.info(f"try again in 10 sec. => {wallet}") 495 | sleeping(10, 10) 496 | okx_withdraw(privatekey, retry+1) 497 | else: 498 | list_send.append(f'{STR_CANCEL}okx_withdraw') 499 | 500 | def get_orbiter_value(amount_to_bridge, to_chain): 501 | 502 | min_amount_to_bridge = 0.011001 503 | 504 | if amount_to_bridge < 0.10101: 505 | decimal.getcontext().prec = 17 506 | elif amount_to_bridge > 1.001: 507 | decimal.getcontext().prec = 15 508 | else: 509 | decimal.getcontext().prec = 18 510 | 511 | if amount_to_bridge >= min_amount_to_bridge: 512 | 513 | amount_to_chain = ORBITER_AMOUNT[to_chain] 514 | str_amount_to_chain = ORBITER_AMOUNT_STR[to_chain] 515 | 516 | while True: 517 | 518 | try: 519 | amount = random.uniform(0.001, 0.0015) 520 | amount = round(amount_to_bridge - amount, 18) 521 | amount = round(amount, 14) 522 | amount = decimal.Decimal(amount) + decimal.Decimal(amount_to_chain) 523 | 524 | while True: 525 | # cprint(amount, 'yellow') 526 | if str(amount)[-4:] == str_amount_to_chain: 527 | break 528 | amount = random.uniform(0.0010, 0.0015) 529 | amount = round(amount_to_bridge - amount, 18) 530 | amount = round(amount, 14) 531 | amount = decimal.Decimal(amount) + decimal.Decimal(amount_to_chain) 532 | 533 | break 534 | 535 | except Exception as ex: 536 | logger.error(ex) 537 | time.sleep(5) 538 | 539 | return amount 540 | 541 | else: 542 | logger.error(f'amount_to_bridge < {min_amount_to_bridge}') 543 | return 0 544 | 545 | def orbiter_bridge(privatekey, retry=0): 546 | 547 | try: 548 | 549 | from_chain, to_chain, bridge_all_balance, amount_from, amount_to, min_amount_bridge, keep_value_from, keep_value_to = value_orbiter() 550 | 551 | keep_value = round(random.uniform(keep_value_from, keep_value_to), 8) 552 | 553 | module_str = f'orbiter_bridge : {from_chain} => {to_chain}' 554 | 555 | if bridge_all_balance == True: 556 | amount_to_bridge = check_balance(privatekey, from_chain, '') 557 | amount_to_bridge = amount_to_bridge - random.uniform(0.002, 0.003) - keep_value 558 | else: amount_to_bridge = round(random.uniform(amount_from, amount_to), 8) 559 | amount_to_bridge = amount_to_bridge 560 | 561 | logger.info('getting right amount') 562 | amount = get_orbiter_value(amount_to_bridge, to_chain) # получаем нужный amount 563 | value = intToDecimal(amount, 18) 564 | 565 | web3 = Web3(Web3.HTTPProvider(DATA[from_chain]['rpc'])) 566 | account = web3.eth.account.from_key(privatekey) 567 | wallet = account.address 568 | chain_id = web3.eth.chain_id 569 | nonce = web3.eth.get_transaction_count(wallet) 570 | 571 | if (amount > 0 and amount >= min_amount_bridge): 572 | 573 | contract_txn = { 574 | 'chainId': chain_id, 575 | 'nonce': nonce, 576 | 'to': '0x80C67432656d59144cEFf962E8fAF8926599bCF8', 577 | 'value': value, 578 | 'gasPrice': 0, 579 | } 580 | 581 | contract_txn = add_gas_price(web3, contract_txn) 582 | contract_txn = add_gas_limit(web3, contract_txn) 583 | 584 | tx_hash = sign_tx(web3, contract_txn, privatekey) 585 | tx_link = f'{DATA[from_chain]["scan"]}/{tx_hash}' 586 | 587 | status = check_status_tx(from_chain, tx_hash) 588 | if status == 1: 589 | logger.success(f'{module_str} | {tx_link}') 590 | list_send.append(f'{STR_DONE}{module_str}') 591 | 592 | else: 593 | if retry < RETRY: 594 | logger.info(f'{module_str} | tx is failed, try again in 10 sec | {tx_link}') 595 | sleeping(10, 10) 596 | transfer(privatekey, retry+1) 597 | else: 598 | logger.error(f'{module_str} | tx is failed | {tx_link}') 599 | 600 | else: 601 | logger.error(f"{module_str} : can't bridge : {amount} (amount) < {min_amount_bridge} (min_amount_bridge)") 602 | list_send.append(f'{STR_CANCEL}{module_str} : {amount} < {min_amount_bridge}') 603 | 604 | except Exception as error: 605 | 606 | logger.error(f'{module_str} | {error}') 607 | if retry < RETRY: 608 | logger.info(f'try again | {wallet}') 609 | sleeping(10, 10) 610 | transfer(privatekey, retry+1) 611 | else: 612 | list_send.append(f'{STR_CANCEL}{module_str}') 613 | 614 | def woofi_get_min_amount(chain, from_token, to_token, amount): 615 | 616 | try: 617 | 618 | slippage = 0.98 619 | 620 | web3 = Web3(Web3.HTTPProvider(DATA[chain]['rpc'])) 621 | address_contract = web3.to_checksum_address(WOOFI_SWAP_CONTRACTS[chain]) 622 | contract = web3.eth.contract(address=address_contract, abi=ABI_WOOFI_SWAP) 623 | 624 | from_token = Web3.to_checksum_address(from_token) 625 | to_token = Web3.to_checksum_address(to_token) 626 | 627 | minToAmount = contract.functions.tryQuerySwap( 628 | from_token, 629 | to_token, 630 | amount 631 | ).call() 632 | 633 | return int(minToAmount * slippage) 634 | 635 | except Exception as error: 636 | logger.error(f'error : {error}. return 0') 637 | return 0 638 | 639 | def woofi_bridge(privatekey, from_chain, to_chain, from_token, to_token, swap_all_balance, amount_from, amount_to, min_amount_swap, keep_value_from, keep_value_to, retry=0): 640 | 641 | try: 642 | 643 | def get_srcInfos(amount_, from_chain, from_token): 644 | 645 | web3 = Web3(Web3.HTTPProvider(DATA[from_chain]['rpc'])) 646 | 647 | from_token = Web3.to_checksum_address(from_token) 648 | 649 | if from_token != '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE': 650 | token_contract, decimals, symbol = check_data_token(web3, from_token) 651 | else: decimals = 18 652 | 653 | amount = intToDecimal(amount_, decimals) 654 | bridgeToken = WOOFI_PATH[from_chain] 655 | minBridgeAmount = woofi_get_min_amount(from_chain, from_token, WOOFI_PATH[from_chain], amount) 656 | 657 | from_token = Web3.to_checksum_address(from_token) 658 | bridgeToken = Web3.to_checksum_address(bridgeToken) 659 | 660 | srcInfos = [ 661 | from_token, 662 | bridgeToken, 663 | amount, 664 | minBridgeAmount 665 | ] 666 | 667 | return srcInfos 668 | 669 | def get_dstInfos(amount, to_chain, to_token): 670 | 671 | chainId = LAYERZERO_CHAINS_ID[to_chain] 672 | 673 | minToAmount = woofi_get_min_amount(to_chain, WOOFI_PATH[to_chain], to_token, amount) 674 | bridgeToken = WOOFI_PATH[to_chain] 675 | 676 | bridgeToken = Web3.to_checksum_address(bridgeToken) 677 | to_token = Web3.to_checksum_address(to_token) 678 | 679 | dstInfos = [ 680 | chainId, 681 | to_token, # toToken 682 | bridgeToken, # bridgeToken 683 | minToAmount, # minToAmount 684 | 0 # airdropNativeAmount 685 | ] 686 | 687 | return dstInfos 688 | 689 | module_str = f'woofi_bridge : {from_chain} => {to_chain}' 690 | logger.info(module_str) 691 | 692 | keep_value = round(random.uniform(keep_value_from, keep_value_to), 8) 693 | if swap_all_balance == True: amount_ = check_balance(privatekey, from_chain, from_token) - keep_value 694 | else: amount_ = round(random.uniform(amount_from, amount_to), 8) 695 | 696 | web3 = Web3(Web3.HTTPProvider(DATA[from_chain]['rpc'])) 697 | address_contract = web3.to_checksum_address( 698 | WOOFI_BRIDGE_CONTRACTS[from_chain] 699 | ) 700 | 701 | if from_token != '': 702 | token_contract, decimals, symbol = check_data_token(web3, from_token) 703 | else: 704 | decimals = 18 705 | 706 | contract = web3.eth.contract(address=address_contract, abi=ABI_WOOFI_BRIDGE) 707 | wallet = web3.eth.account.from_key(privatekey).address 708 | 709 | if to_token == '' : to_token = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' 710 | if from_token == '' : from_token = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' 711 | 712 | amount = intToDecimal(amount_, decimals) 713 | srcInfos = get_srcInfos(amount_, from_chain, from_token) 714 | dstInfos = get_dstInfos(srcInfos[3], to_chain, to_token) 715 | 716 | # cprint(f'\nsrcInfos : {srcInfos}\ndstInfos : {dstInfos}', 'blue') 717 | 718 | # если токен не нативный, тогда проверяем апрув и если он меньше нужного, делаем апруваем 719 | if from_token != '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE': 720 | allowance_amount = check_allowance(from_chain, from_token, wallet, WOOFI_BRIDGE_CONTRACTS[from_chain]) 721 | if amount > allowance_amount: 722 | approve_(privatekey, from_chain, from_token, WOOFI_BRIDGE_CONTRACTS[from_chain]) 723 | sleeping(5, 10) 724 | 725 | while True: 726 | try: 727 | fees = contract.functions.quoteLayerZeroFee( 728 | random.randint(112101680502565000, 712101680502565000), # refId 729 | wallet, # to 730 | srcInfos, 731 | dstInfos 732 | ).call() 733 | break 734 | except Exception as error: 735 | logger.error(error) 736 | time.sleep(1) 737 | 738 | if from_token == '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE': 739 | value = int(amount + fees[0]) 740 | else: 741 | value = int(fees[0]) 742 | 743 | if amount_ >= min_amount_swap: 744 | contract_txn = contract.functions.crossSwap( 745 | random.randint(112101680502565000, 712101680502565000), # refId 746 | wallet, # to 747 | srcInfos, 748 | dstInfos 749 | ).build_transaction( 750 | { 751 | 'from': wallet, 752 | 'nonce': web3.eth.get_transaction_count(wallet), 753 | 'value': value, 754 | 'gasPrice': 0, 755 | 'gas': 0, 756 | } 757 | ) 758 | 759 | contract_txn = add_gas_price(web3, contract_txn) 760 | contract_txn = add_gas_limit(web3, contract_txn) 761 | 762 | tx_hash = sign_tx(web3, contract_txn, privatekey) 763 | tx_link = f'{DATA[from_chain]["scan"]}/{tx_hash}' 764 | 765 | status = check_status_tx(from_chain, tx_hash) 766 | if status == 1: 767 | logger.success(f'{module_str} | {tx_link}') 768 | list_send.append(f'{STR_DONE}{module_str}') 769 | time.sleep(3) 770 | 771 | else: 772 | logger.error(f'{module_str} | tx is failed | {tx_link}') 773 | 774 | retry += 1 775 | if retry < RETRY: 776 | logger.info(f'try again | {wallet}') 777 | time.sleep(3) 778 | # woofi_bridge(privatekey, from_chain, to_chain, from_token, to_token, swap_all_balance, amount_from, amount_to, min_amount_swap, keep_value_from, keep_value_to, retry+1) 779 | else: 780 | list_send.append(f'{STR_CANCEL}{module_str}') 781 | 782 | else: 783 | logger.error(f"{module_str} : can't bridge : {amount_} (amount) < {min_amount_swap} (min_amount_swap)") 784 | list_send.append(f'{STR_CANCEL}{module_str} : {amount_} < {min_amount_swap}') 785 | 786 | except Exception as error: 787 | logger.error(f'{module_str} | error : {error}') 788 | if retry < RETRY: 789 | logger.info(f'try again in 10 sec.') 790 | sleeping(10, 10) 791 | woofi_bridge(privatekey, retry+1) 792 | else: 793 | list_send.append(f'{STR_CANCEL}{module_str}') 794 | 795 | def woofi_swap(privatekey, from_chain, from_token, to_token, swap_all_balance, amount_from, amount_to, min_amount_swap, keep_value_from, keep_value_to, retry=0): 796 | 797 | try: 798 | 799 | module_str = f'woofi_swap : {from_chain}' 800 | logger.info(module_str) 801 | 802 | keep_value = round(random.uniform(keep_value_from, keep_value_to), 8) 803 | if swap_all_balance == True: amount_ = check_balance(privatekey, from_chain, from_token) - keep_value 804 | else: amount_ = round(random.uniform(amount_from, amount_to), 8) 805 | 806 | web3 = Web3(Web3.HTTPProvider(DATA[from_chain]['rpc'])) 807 | address_contract = web3.to_checksum_address( 808 | WOOFI_SWAP_CONTRACTS[from_chain] 809 | ) 810 | 811 | if from_token != '': 812 | token_contract, decimals, symbol = check_data_token(web3, from_token) 813 | else: 814 | decimals = 18 815 | 816 | contract = web3.eth.contract(address=address_contract, abi=ABI_WOOFI_SWAP) 817 | wallet = web3.eth.account.from_key(privatekey).address 818 | 819 | amount = intToDecimal(amount_, decimals) 820 | 821 | # если токен не нативный, тогда проверяем апрув и если он меньше нужного, делаем апруваем 822 | if from_token != '': 823 | allowance_amount = check_allowance(from_chain, from_token, wallet, WOOFI_SWAP_CONTRACTS[from_chain]) 824 | if amount > allowance_amount: 825 | approve_(privatekey, from_chain, from_token, WOOFI_SWAP_CONTRACTS[from_chain]) 826 | sleeping(5, 10) 827 | 828 | if to_token == '' : to_token = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' 829 | if from_token == '' : 830 | from_token = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' 831 | value = amount 832 | else: 833 | value = 0 834 | 835 | minToAmount = woofi_get_min_amount(from_chain, from_token, to_token, amount) 836 | 837 | if amount_ >= min_amount_swap: 838 | contract_txn = contract.functions.swap( 839 | from_token, 840 | to_token, 841 | amount, 842 | minToAmount, 843 | wallet, 844 | wallet 845 | ).build_transaction( 846 | { 847 | 'from': wallet, 848 | 'nonce': web3.eth.get_transaction_count(wallet), 849 | 'value': value, 850 | 'gasPrice': 0, 851 | 'gas': 0, 852 | } 853 | ) 854 | 855 | contract_txn = add_gas_price(web3, contract_txn) 856 | contract_txn = add_gas_limit(web3, contract_txn) 857 | 858 | tx_hash = sign_tx(web3, contract_txn, privatekey) 859 | tx_link = f'{DATA[from_chain]["scan"]}/{tx_hash}' 860 | 861 | status = check_status_tx(from_chain, tx_hash) 862 | if status == 1: 863 | logger.success(f'{module_str} | {tx_link}') 864 | list_send.append(f'{STR_DONE}{module_str}') 865 | time.sleep(3) 866 | 867 | else: 868 | logger.error(f'{module_str} | tx is failed | {tx_link}') 869 | retry += 1 870 | if retry < RETRY: 871 | logger.info(f'try again | {wallet}') 872 | time.sleep(3) 873 | # woofi_swap(privatekey, from_chain, from_token, to_token, swap_all_balance, amount_from, amount_to, min_amount_swap, keep_value_from, keep_value_to, retry+1) 874 | else: 875 | list_send.append(f'{STR_CANCEL}{module_str}') 876 | 877 | else: 878 | logger.error(f"{module_str} : can't swap : {amount_} (amount) < {min_amount_swap} (min_amount_swap)") 879 | list_send.append(f'{STR_CANCEL}{module_str} : {amount_} < {min_amount_swap}') 880 | 881 | except Exception as error: 882 | logger.error(f'{module_str} | error : {error}') 883 | if retry < RETRY: 884 | logger.info(f'try again in 10 sec.') 885 | sleeping(10, 10) 886 | woofi_bridge(privatekey, retry+1) 887 | else: 888 | list_send.append(f'{STR_CANCEL}{module_str}') 889 | 890 | def woofi(privatekey): 891 | 892 | from_chain, to_chain, from_token, to_token, swap_all_balance, amount_from, amount_to, min_amount_swap, keep_value_from, keep_value_to = value_woofi() 893 | 894 | if from_chain == to_chain: 895 | woofi_swap(privatekey, from_chain, from_token, to_token, swap_all_balance, amount_from, amount_to, min_amount_swap, keep_value_from, keep_value_to) 896 | else: 897 | woofi_bridge(privatekey, from_chain, to_chain, from_token, to_token, swap_all_balance, amount_from, amount_to, min_amount_swap, keep_value_from, keep_value_to) 898 | 899 | def exchange_withdraw(privatekey, retry=0): 900 | 901 | try: 902 | 903 | cex, chain, symbol, amount_from, amount_to = value_exchange() 904 | amount_ = round(random.uniform(amount_from, amount_to), 7) 905 | 906 | API_KEY = CEX_KEYS[cex]['api_key'] 907 | API_SECRET = CEX_KEYS[cex]['api_secret'] 908 | 909 | wallet = evm_wallet(privatekey) 910 | 911 | dict_ = { 912 | 'apiKey': API_KEY, 913 | 'secret': API_SECRET, 914 | 'enableRateLimit': True, 915 | 'options': { 916 | 'defaultType': 'spot' 917 | } 918 | } 919 | 920 | if cex in ['kucoin']: 921 | dict_['password'] = CEX_KEYS[cex]['password'] 922 | 923 | account = ccxt.__dict__[cex](dict_) 924 | 925 | account.withdraw( 926 | code = symbol, 927 | amount = amount_, 928 | address = wallet, 929 | tag = None, 930 | params = { 931 | "network": chain 932 | } 933 | ) 934 | logger.success(f"{cex}_withdraw success => {wallet} | {amount_} {symbol}") 935 | list_send.append(f'{STR_DONE}{cex}_withdraw') 936 | 937 | except Exception as error: 938 | logger.error(f"{cex}_withdraw unsuccess => {wallet} | error : {error}") 939 | list_send.append(f'{STR_CANCEL}{cex}_withdraw') 940 | 941 | --------------------------------------------------------------------------------