Skip to content

Instantly share code, notes, and snippets.

@brianddk
Last active May 10, 2021 18:33
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brianddk/e655a2a30f68cd5d981b69ec4b709d9c to your computer and use it in GitHub Desktop.
Save brianddk/e655a2a30f68cd5d981b69ec4b709d9c to your computer and use it in GitHub Desktop.
Trezor HW wallet search utility
#!/usr/bin/env python3
# [rights] Copyright Dan B. (brianddk) 2019 https://github.com/brianddk
# [license] Apache 2.0 License https://www.apache.org/licenses/LICENSE-2.0
# [repo] https://gist.github.com/brianddk/e655a2a30f68cd5d981b69ec4b709d9c
# [tipjar] LTC: LQjSwZLigtgqHA3rE14yeRNbNNY2r3tXcA or https://git.io/fh6b0
# [refered] https://www.reddit.com/r/TREZOR/comments/ak2mej/
# [erratta] https://github.com/pyusb/pyusb/issues/203
# - Must use libusb-1.0.dll v1.0.21
# https://github.com/ethereum/pyethereum/issues/888
# - Must install trezor[hidapi]
# - Capricoin and GameCredits are excluded due to poor support
# [notes] Full run takes about an hour. Most of the time is spent on
# address queries to the Trezor device. This can be optimized by
# likely by 95% by simply pulling the XPUB addresses then
# generating the individual address via nodeJS using the bitcoinjs
# library. There are likely python libraries that do the same, so
# if anyone is familiar with them, please PR or post comments.
from trezorlib.client import TrezorClient
from trezorlib.transport import get_transport
from trezorlib.tools import parse_path
from trezorlib import btc, ethereum, messages
from trezorlib.ui import ClickUI
# from os.path import isfile
import urllib.request
import json
import glob
def get_ethereum_address(path):
transport = get_transport()
ui = ClickUI()
address = 'Error'
try:
client = TrezorClient(transport, ui)
address = ethereum.get_address(client, parse_path(path))
except Exception:
pass
finally:
client.close()
return '0x' + address.hex()
def get_address(coin, path, addr_type):
if addr_type == 'address':
script_type = messages.InputScriptType.SPENDADDRESS
if addr_type == 'p2shsegwit':
script_type = messages.InputScriptType.SPENDP2SHWITNESS
if addr_type == 'segwit':
script_type = messages.InputScriptType.SPENDWITNESS
transport = get_transport()
ui = ClickUI()
address = 'Error'
try:
client = TrezorClient(transport, ui)
address = btc.get_address(client, coin['coin_name'], parse_path(path), show_display=False, multisig=None, script_type=script_type)
except Exception:
pass
finally:
client.close()
return address
def get_path(coin, addr_type, account, change, index):
if addr_type == 'address':
path = "m/44'/" + str(coin['slip44']) + "'/" + str(account) + "'/" + str(change) + "/" + str(index)
if addr_type == 'p2shsegwit':
path = "m/49'/" + str(coin['slip44']) + "'/" + str(account) + "'/" + str(change) + "/" + str(index)
if addr_type == 'segwit':
path = "m/84'/" + str(coin['slip44']) + "'/" + str(account) + "'/" + str(change) + "/" + str(index)
return path
def get_coins():
coins = []
files = ['trezor-common/defs/ethereum/networks.json']
for filename in glob.glob('trezor-common/defs/bitcoin/*.json'):
files.append(filename.replace('\\', '/'))
for filename in glob.glob('custom/*.json'):
files.append(filename.replace('\\', '/'))
for file in files:
with open(file) as json_data:
coin = json.load(json_data)
if type(coin) is dict:
coin = [coin]
for item in coin:
if not item['blockbook']:
continue
if ('chain_id' in item) and (item['slip44'] < 60):
continue
if 'name' in item:
item['coin_name'] = item['name']
item['coin_label'] = item['name']
if item['coin_name'] == 'Capricoin':
continue
if item['coin_name'] == 'GameCredits':
continue
if 'segwit' not in item:
item['segwit'] = False
coins.append(item)
return coins
def verify_coins(coins):
verified = []
for coin in coins:
for url in coin['blockbook']:
url += "/api/"
q = urllib.request.Request(url)
q.add_header('User-Agent', 'curl/7.55.1')
try:
with urllib.request.urlopen(q) as req:
data = req.read().decode()
if(data.replace(' ', '').find('"inSync":true') >= 0):
coin['api'] = url
break
except Exception:
pass
if 'coin_label' in coin:
label = coin['coin_label']
else:
label = coin['coin_name']
if 'api' in coin:
print("ADDING:", label)
verified.append(coin)
else:
print("FAILED:", label)
return verified
def get_address_info(coin, address):
url = coin['api'] + 'address/' + address
q = urllib.request.Request(url)
q.add_header('User-Agent', 'curl/7.55.1')
try:
with urllib.request.urlopen(q) as req:
data = json.loads(req.read().decode())
except Exception:
raise
return data
def main():
coins = get_coins()
coins = verify_coins(coins)
max_accounts = 2
max_addresses = 4
for coin in coins:
account = -1
blank_accounts = 0
while(blank_accounts < max_accounts):
account += 1
blank_accounts += 1
if coin['segwit']:
types = ['address', 'p2shsegwit', 'segwit']
else:
types = ['address']
for addr_type in types:
index = -1
blank_addresses = 0
while (blank_addresses < max_addresses):
index += 1
blank_addresses += 1
for change in [0, 1]:
for fmt_type in types:
path = get_path(coin, addr_type, account, change, index)
# print(blank_accounts, blank_addresses, path, fmt_type)
if 'chain_id' in coin:
address = get_ethereum_address(path)
else:
address = get_address(coin, path, fmt_type)
try:
addr_info = get_address_info(coin, address)
except Exception:
print("ERROR:", coin['coin_label'], path, address)
addr_info = {'txApperances': 0}
if ('txApperances' in addr_info) and (addr_info['txApperances'] > 0):
blank_accounts = blank_addresses = 0
print("ACTIVE:", coin['coin_label'], path, address)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment