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

323 lines
11 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
import ethereum_tokens_gen
COINS = {}
def coinmarketcap_init():
global COINS
try:
COINS = json.load(open('coinmarketcap.json', 'r'))
except FileNotFoundError:
pass
else:
if COINS["1"]["last_updated"] > time.time() - 3600:
print("Using local cache of coinmarketcap")
return
print("Updating coins from coinmarketcap")
total = None
COINS = {}
while total is None or len(COINS) < total:
url = 'https://api.coinmarketcap.com/v2/ticker/?start=%d&convert=USD&limit=100' % (len(COINS)+1)
data = requests.get(url).json()
COINS.update(data['data'])
if total is None:
total = data['metadata']['num_cryptocurrencies']
print("Fetched %d of %d coins" % (len(COINS), total))
time.sleep(1)
json.dump(COINS, open('coinmarketcap.json', 'w'), sort_keys=True, indent=4)
def coinmarketcap_info(shortcut):
global COINS
shortcut = shortcut.replace(' ', '-').lower()
for _id in COINS:
coin = COINS[_id]
#print(shortcut, coin['website_slug'])
if shortcut == coin['website_slug']:
#print(coin)
return coin
def update_marketcap(obj, shortcut):
try:
obj['marketcap_usd'] = int(float(coinmarketcap_info(shortcut)['quotes']['USD']['market_cap']))
except:
pass
# print("Marketcap info not found for", shortcut)
def coinmarketcap_global():
url = 'https://api.coinmarketcap.com/v2/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' and not c.get('hidden', False)])
details['info']['t2_coins'] = len([True for _, c in details['coins'].items() if c['t2_enabled'] == 'yes' and not c.get('hidden', False)])
try:
details['info']['total_marketcap_usd'] = int(coinmarketcap_global()['data']['quotes']['USD']['total_market_cap'])
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',
'exp',
# 'rop',
# 'rin',
'ubq',
# 'rsk',
# 'kov',
'etc',
]
LATEST_T1 = 'https://raw.githubusercontent.com/trezor/trezor-mcu/v1.6.1/firmware/ethereum_tokens.c'
LATEST_T2 = 'https://raw.githubusercontent.com/trezor/trezor-core/v2.0.6/src/apps/ethereum/tokens.py'
tokens = ethereum_tokens_gen.get_tokens()
tokens_t1 = requests.get(LATEST_T1).text
tokens_t2 = requests.get(LATEST_T2).text
supported = []
for t in tokens:
# print('Updating', t['symbol'])
if t['chain'] not in networks:
print('Skipping, %s is disabled' % t['chain'])
continue
key = "erc20:%s:%s" % (t['chain'], t['symbol'])
supported.append(key)
out = details['coins'].setdefault(key, {})
out['type'] = 'erc20'
out['network'] = t['chain']
out['address'] = t['address']
set_default(out, 'shortcut', t['symbol'])
set_default(out, 'name', t['name'])
set_default(out, 'links', {})
if "\" %s\"" % t['symbol'] in tokens_t1:
out['t1_enabled'] = 'yes'
else:
out['t1_enabled'] = 'soon'
if "'%s'" % t['symbol'] in tokens_t2:
out['t2_enabled'] = 'yes'
else:
out['t2_enabled'] = 'soon'
out['links']['MyCrypto Wallet'] = 'https://mycrypto.com'
out['links']['MyEtherWallet'] = 'https://www.myetherwallet.com'
if t['website']:
out['links']['Homepage'] = t['website']
if t.get('social', {}).get('github', None):
out['links']['Github'] = t['social']['github']
update_marketcap(out, out.get('coinmarketcap_alias', t['symbol']))
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')
out = details['coins'].setdefault('coin2:ELLA', {})
out['type'] = 'coin'
set_default(out, 'shortcut', 'ELLA')
set_default(out, 'name', 'Ellaism')
set_default(out, 't1_enabled', 'yes')
set_default(out, 't2_enabled', 'yes')
update_marketcap(out, 'ellaism')
out = details['coins'].setdefault('coin2:EGEM', {})
out['type'] = 'coin'
set_default(out, 'shortcut', 'EGEM')
set_default(out, 'name', 'EtherGem')
set_default(out, 't1_enabled', 'yes')
set_default(out, 't2_enabled', 'yes')
update_marketcap(out, 'egem')
out = details['coins'].setdefault('coin2:ETSC', {})
out['type'] = 'coin'
set_default(out, 'shortcut', 'ETSC')
set_default(out, 'name', 'EthereumSocial')
set_default(out, 't1_enabled', 'yes')
set_default(out, 't2_enabled', 'yes')
update_marketcap(out, 'etsc')
ut = details['coins'].setdefault('coin2:EOSC', {})
out['type'] = 'coin'
set_default(out, 'shortcut', 'EOSC')
set_default(out, 'name', 'EOS Classic')
set_default(out, 't1_enabled', 'yes')
set_default(out, 't2_enabled', 'yes')
update_marketcap(out, 'eosc')
def update_mosaics(details):
d = json.load(open('defs/nem/nem_mosaics.json'))
supported = []
for mosaic in d:
# 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]
hide = False
if 'links' not in coin:
print("%s: Missing links" % k)
hide = True
if 'Homepage' not in coin['links']:
print("%s: Missing homepage" % k)
hide = True
if coin['t1_enabled'] not in ('yes', 'no', 'planned', 'soon'):
print("%s: Unknown t1_enabled" % k)
hide = True
if coin['t2_enabled'] not in ('yes', 'no', 'planned', 'soon'):
print("%s: Unknown t2_enabled" % k)
hide = True
if 'TREZOR Wallet' in coin['links'] and coin['links']['TREZOR Wallet'] != 'https://wallet.trezor.io':
print("%s: Strange URL for TREZOR Wallet" % k)
hide = True
for w in [ x.lower() for x in coin['links'].keys() ]:
if 'wallet' in w or 'electrum' in w:
break
else:
if coin['t1_enabled'] == 'yes' or coin['t2_enabled'] == 'yes':
print("%s: Missing wallet" % k)
hide = True
else:
print("%s: Missing wallet, but not hiding" % k)
if hide:
# If any of important detail is missing, hide coin from list
coin['hidden'] = 1
if not hide and coin.get('hidden'):
print("%s: Details are OK, but coin is still hidden" % k)
for k in details['coins'].keys():
if details['coins'][k].get('hidden') == 1:
print("%s: Coin is hidden" % k)
if __name__ == '__main__':
try:
details = json.load(open('coins_details.json', 'r'))
except FileNotFoundError:
details = {'coins': {}, 'info': {}}
coinmarketcap_init()
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)