You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/coins_details.py

242 lines
8.2 KiB

#!/usr/bin/env python3
"""Fetch information about coins and tokens supported by Trezor and update it in coins_details.json."""
import time
import json
import requests
import pprint
SKIP_COINMARKETCAP = True
def coinmarketcap_info(shortcut):
if SKIP_COINMARKETCAP:
raise Exception("Skipping coinmarketcap call")
shortcut = shortcut.replace(' ', '-')
url = 'https://api.coinmarketcap.com/v1/ticker/%s/?convert=USD' % shortcut
try:
return requests.get(url).json()[0]
except KeyboardInterrupt:
raise
except:
print("Cannot fetch Coinmarketcap info for %s" % shortcut)
def update_marketcap(obj, shortcut):
try:
obj['marketcap_usd'] = int(float(coinmarketcap_info(shortcut)['market_cap_usd']))
except:
pass
def coinmarketcap_global():
if SKIP_COINMARKETCAP:
raise Exception("Skipping coinmarketcap call")
url = 'https://api.coinmarketcap.com/v1/global'
ret = requests.get(url)
data = ret.json()
return data
def set_default(obj, key, default_value):
obj[key] = obj.setdefault(key, default_value)
def update_info(details):
details['info']['updated_at'] = int(time.time())
details['info']['updated_at_readable'] = time.asctime()
details['info']['t1_coins'] = len([True for _, c in details['coins'].items() if c['t1_enabled'] == 'yes'])
details['info']['t2_coins'] = len([True for _, c in details['coins'].items() if c['t2_enabled'] == 'yes'])
try:
details['info']['total_marketcap_usd'] = int(coinmarketcap_global()['total_market_cap_usd'])
except:
pass
marketcap = 0
for k, c in details['coins'].items():
if c['t1_enabled'] == 'yes' or c['t2_enabled'] == 'yes':
marketcap += details['coins'][k].setdefault('marketcap_usd', 0)
details['info']['marketcap_usd'] = marketcap
def check_unsupported(details, prefix, supported):
for k in details['coins'].keys():
if not k.startswith(prefix):
continue
if k not in supported:
print("%s not supported by Trezor? (Possible manual entry)" % k)
def update_coins(details):
coins = json.load(open('coins.json', 'r'))
supported = []
for coin in coins:
if coin['firmware'] != 'stable':
continue
# print("Updating", coin['coin_label'], coin['coin_shortcut'])
key = "coin:%s" % coin['coin_shortcut']
supported.append(key)
out = details['coins'].setdefault(key, {})
out['type'] = 'coin'
set_default(out, 'shortcut', coin['coin_shortcut'])
set_default(out, 'name', coin['coin_label'])
set_default(out, 'links', {})
set_default(out, 't1_enabled', 'yes')
set_default(out, 't2_enabled', 'yes')
update_marketcap(out, coin.get('coinmarketcap_alias', coin['coin_label']))
check_unsupported(details, 'coin:', supported)
def update_erc20(details):
networks = [
('eth', 1),
# ('exp', 2),
# ('rop', 3),
('rin', 4),
('ubq', 8),
# ('rsk', 30),
('kov', 42),
('etc', 61),
]
# Fetch list of tokens already included in Trezor Core
r = requests.get('https://raw.githubusercontent.com/trezor/trezor-core/master/src/apps/ethereum/tokens.py')
d = {}
exec(r.text, d)
# TODO 'Qmede...' can be removed after ipfs_hash is being generated into tokens.py
ipfs_hash = d.get('ipfs_hash') or 'QmedefcF1fecLVpRymJJmyJFRpJuCTiNfPYBhzUdHPUq3T'
infos = {}
for n in networks:
# print("Updating info about erc20 tokens for", n[0])
url = 'https://gateway.ipfs.io/ipfs/%s/%s.json' % (ipfs_hash, n[0])
r = requests.get(url)
infos[n[0]] = r.json()
supported = []
for t in d['tokens']:
token = t[2]
# print('Updating', token)
try:
network = [ n[0] for n in networks if n[1] == t[0] ][0]
except:
raise Exception("Unknown network", t[0], "for erc20 token", token)
try:
info = [ i for i in infos[network] if i['symbol'] == token ][0]
except:
raise Exception("Unknown details for erc20 token", token)
key = "erc20:%s:%s" % (network, token)
supported.append(key)
out = details['coins'].setdefault(key, {})
out['type'] = 'erc20'
out['network'] = network
out['address'] = info['address']
set_default(out, 'shortcut', token)
set_default(out, 'name', info['name'])
set_default(out, 't1_enabled', 'yes')
set_default(out, 't2_enabled', 'yes')
set_default(out, 'links', {})
if info['website']:
out['links']['Homepage'] = info['website']
if info.get('social', {}).get('github', None):
out['links']['Github'] = info['social']['github']
update_marketcap(out, out.get('coinmarketcap_alias', token))
check_unsupported(details, 'erc20:', supported)
def update_ethereum(details):
out = details['coins'].setdefault('coin2:ETH', {})
out['type'] = 'coin'
set_default(out, 'shortcut', 'ETH')
set_default(out, 'name', 'Ethereum')
set_default(out, 't1_enabled', 'yes')
set_default(out, 't2_enabled', 'yes')
update_marketcap(out, 'ethereum')
out = details['coins'].setdefault('coin2:ETC', {})
out['type'] = 'coin'
set_default(out, 'shortcut', 'ETC')
set_default(out, 'name', 'Ethereum Classic')
set_default(out, 't1_enabled', 'yes')
set_default(out, 't2_enabled', 'yes')
update_marketcap(out, 'ethereum-classic')
out = details['coins'].setdefault('coin2:RSK', {})
out['type'] = 'coin'
set_default(out, 'shortcut', 'RSK')
set_default(out, 'name', 'Rootstock')
set_default(out, 't1_enabled', 'yes')
set_default(out, 't2_enabled', 'yes')
update_marketcap(out, 'rootstock')
out = details['coins'].setdefault('coin2:EXP', {})
out['type'] = 'coin'
set_default(out, 'shortcut', 'EXP')
set_default(out, 'name', 'Expanse')
set_default(out, 't1_enabled', 'yes')
set_default(out, 't2_enabled', 'yes')
update_marketcap(out, 'expanse')
out = details['coins'].setdefault('coin2:UBQ', {})
out['type'] = 'coin'
set_default(out, 'shortcut', 'UBQ')
set_default(out, 'name', 'Ubiq')
set_default(out, 't1_enabled', 'yes')
set_default(out, 't2_enabled', 'yes')
update_marketcap(out, 'ubiq')
def update_mosaics(details):
r = requests.get('https://raw.githubusercontent.com/trezor/trezor-mcu/master/firmware/nem_mosaics.json')
supported = []
for mosaic in r.json():
# print('Updating', mosaic['name'], mosaic['ticker'])
key = "mosaic:%s" % mosaic['ticker'].strip()
supported.append(key)
out = details['coins'].setdefault(key, {})
out['type'] = 'mosaic'
set_default(out, 'shortcut', mosaic['ticker'].strip())
set_default(out, 'name', mosaic['name'])
set_default(out, 't1_enabled', 'yes')
set_default(out, 't2_enabled', 'yes')
update_marketcap(out, out.get('coinmarketcap_alias', out['name']))
check_unsupported(details, 'mosaic:', supported)
def check_missing_details(details):
for k in details['coins'].keys():
coin = details['coins'][k]
if 'links' not in coin:
print("%s: Missing links" % k)
continue
if 'Homepage' not in coin['links']:
print("%s: Missing homepage" % k)
if coin['t1_enabled'] not in ('yes', 'no', 'planned', 'in progress'):
print("%s: Unknown t1_enabled" % k)
if coin['t2_enabled'] not in ('yes', 'no', 'planned', 'in progress'):
print("%s: Unknown t2_enabled" % k)
if 'TREZOR Wallet' in coin['links'] and coin['links']['TREZOR Wallet'] != 'https://wallet.trezor.io':
print("%s: Strange URL for TREZOR Wallet" % k)
if __name__ == '__main__':
try:
details = json.load(open('coins_details.json', 'r'))
except FileNotFoundError:
details = {'coins': {}, 'info': {}}
update_coins(details)
update_erc20(details)
update_ethereum(details)
update_mosaics(details)
update_info(details)
check_missing_details(details)
print(json.dumps(details['info'], sort_keys=True, indent=4))
json.dump(details, open('coins_details.json', 'w'), sort_keys=True, indent=4)