-
Notifications
You must be signed in to change notification settings - Fork 109
Expand file tree
/
Copy pathlz.py
More file actions
163 lines (120 loc) · 6.6 KB
/
lz.py
File metadata and controls
163 lines (120 loc) · 6.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
import argparse
import logging
import random
import sys
import time
from typing import Any
from base.errors import NotWhitelistedAddress
from logic import AccountThread
from config import ConfigurationHelper, DEFAULT_PRIVATE_KEYS_FILE_PATH, BridgerMode, RefuelMode
from logger import setup_logger
from exchange import ExchangeFactory
from utility import WalletHelper
logger = logging.getLogger(__name__)
class LayerZeroBridger:
def __init__(self) -> None:
setup_logger()
self.wh = WalletHelper()
def main(self) -> None:
parser = argparse.ArgumentParser(description="layerzero-bridger CLI")
subparsers = parser.add_subparsers(title="subcommands", dest="subcommand")
self._create_generate_parser(subparsers)
self._create_withdraw_parser(subparsers)
self._create_run_bridger_parser(subparsers)
args = parser.parse_args()
if hasattr(args, "func"):
args.func(args)
else:
parser.print_help()
def generate_private_keys(self, args: argparse.Namespace) -> None:
if args.num_keys <= 0:
logger.info("Number of keys must be a positive integer")
sys.exit(1)
filename = args.filename if args.filename else ""
private_keys = []
for _ in range(args.num_keys):
pk = self.wh.generate_private_key()
private_keys.append(pk)
self.wh.to_txt(private_keys, filename)
def withdraw_funds(self, args: argparse.Namespace) -> None:
token = args.token.upper()
network = args.network
private_keys = self.wh.load_private_keys(args.private_keys)
addresses = self.wh.resolve_addresses(private_keys)
if not addresses:
logger.info('You should specify at least 1 address for the withdrawal')
sys.exit(1)
exchange = ExchangeFactory.create(args.exchange)
if not exchange.is_withdraw_supported(token, network):
logger.info(f'{token} withdrawal on the {network} network is not available')
sys.exit(1)
for idx, address in enumerate(addresses):
logger.info(f'Processing {idx}/{len(addresses)}')
amount = random.uniform(args.min_amount, args.max_amount)
decimals = random.randint(3, 6) # May be improved
amount = round(amount, decimals)
try:
exchange.withdraw(token, amount, network, address)
except NotWhitelistedAddress as ex:
logger.info(str(ex))
sys.exit(1)
if idx == len(addresses) - 1:
logger.info('All withdrawals are successfully completed')
sys.exit(0)
waiting_time = random.uniform(args.min_time, args.max_time)
logger.info(f'Waiting {round(waiting_time, 1)} minutes before the next withdrawal')
time.sleep(waiting_time * 60) # Convert waiting time to seconds
def run_bridger(self, args: argparse.Namespace) -> None:
config = ConfigurationHelper()
config.check_configuration()
bridger_mode = BridgerMode(args.bridger_mode)
refuel_mode = RefuelMode(args.refuel_mode)
bridges_limit = args.limit
private_keys = self.wh.load_private_keys(args.private_keys)
if not private_keys:
logger.info("Zero private keys was loaded")
sys.exit(1)
accounts = []
for account_id, private_key in enumerate(private_keys):
accounts.append(AccountThread(account_id, private_key, bridger_mode, refuel_mode, bridges_limit))
accounts[account_id].start()
for account in accounts:
account.join()
def _create_generate_parser(self, subparsers: Any) -> None:
generate_parser = subparsers.add_parser("generate", help="Generate new private keys")
generate_parser.add_argument("num_keys", type=int, help="Number of private keys to generate")
generate_parser.add_argument("filename", nargs="?", help="Path to the file to save the private keys")
generate_parser.set_defaults(func=self.generate_private_keys)
def _create_withdraw_parser(self, subparsers: Any) -> None:
withdraw_parser = subparsers.add_parser("withdraw", help="Withdraw funds from exchange to account addresses")
withdraw_parser.add_argument("token", help="Token to be withdrawn")
withdraw_parser.add_argument("network", choices=["Arbitrum", "Ethereum", "Optimism", "Polygon",
"Fantom", "Avalanche", "BSC"],
help="Network for the withdrawal")
# Amount
withdraw_parser.add_argument("min_amount", type=float, help="Minimum amount of withdrawal")
withdraw_parser.add_argument("max_amount", type=float, help="Maximum amount of withdrawal")
# Waiting time
withdraw_parser.add_argument("--min_time", type=float, default=0, dest="min_time",
help="Minimum waiting time between withdraws in minutes")
withdraw_parser.add_argument("--max_time", type=float, default=0, dest="max_time",
help="Maximum waiting time between withdraws in minutes")
withdraw_parser.add_argument("--keys", type=str, default=DEFAULT_PRIVATE_KEYS_FILE_PATH,
dest="private_keys",
help="Path to the file containing private keys of the account addresses")
withdraw_parser.add_argument("--exchange", choices=["binance", "okex"], default="binance", dest='exchange',
help="Exchange name (binance, okex)")
withdraw_parser.set_defaults(func=self.withdraw_funds)
def _create_run_bridger_parser(self, subparsers: Any) -> None:
run_parser = subparsers.add_parser("run", help="Run the LayerZero bridger")
run_parser.add_argument("bridger_mode", choices=["stargate", "btcb"],
help="Running mode (stargate, btcb)")
run_parser.add_argument("--keys", type=str, default=DEFAULT_PRIVATE_KEYS_FILE_PATH, dest="private_keys",
help="Path to the file containing private keys")
run_parser.add_argument("--refuel", choices=["manual", "binance", "okex"], default="manual", dest='refuel_mode',
help="Refuel mode (manual, binance, okex)")
run_parser.add_argument("--limit", type=int, help="Maximum number of bridges to be executed")
run_parser.set_defaults(func=self.run_bridger)
if __name__ == "__main__":
app = LayerZeroBridger()
app.main()