2018-04-06 20:11:14 +00:00
|
|
|
#!/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
|
2018-05-23 14:42:08 +00:00
|
|
|
import ethereum_tokens_gen
|
2018-04-06 20:11:14 +00:00
|
|
|
|
2018-05-22 17:42:49 +00:00
|
|
|
COINS = {}
|
2018-04-06 20:11:14 +00:00
|
|
|
|
2018-05-22 17:42:49 +00:00
|
|
|
def coinmarketcap_init():
|
|
|
|
global COINS
|
2018-04-06 20:11:14 +00:00
|
|
|
|
|
|
|
try:
|
2018-05-22 17:42:49 +00:00
|
|
|
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
|
2018-04-06 20:11:14 +00:00
|
|
|
|
|
|
|
def update_marketcap(obj, shortcut):
|
|
|
|
try:
|
2018-05-22 17:42:49 +00:00
|
|
|
obj['marketcap_usd'] = int(float(coinmarketcap_info(shortcut)['quotes']['USD']['market_cap']))
|
2018-04-06 20:11:14 +00:00
|
|
|
except:
|
2018-05-25 09:29:37 +00:00
|
|
|
pass
|
|
|
|
# print("Marketcap info not found for", shortcut)
|
2018-04-06 20:11:14 +00:00
|
|
|
|
|
|
|
def coinmarketcap_global():
|
2018-05-22 17:42:49 +00:00
|
|
|
url = 'https://api.coinmarketcap.com/v2/global'
|
2018-04-06 20:11:14 +00:00
|
|
|
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()
|
2018-05-25 09:29:37 +00:00
|
|
|
|
2018-05-24 14:25:44 +00:00
|
|
|
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)])
|
2018-05-16 15:30:28 +00:00
|
|
|
|
2018-04-06 20:11:14 +00:00
|
|
|
try:
|
2018-05-22 17:42:49 +00:00
|
|
|
details['info']['total_marketcap_usd'] = int(coinmarketcap_global()['data']['quotes']['USD']['total_market_cap'])
|
2018-04-06 20:11:14 +00:00
|
|
|
except:
|
|
|
|
pass
|
|
|
|
|
|
|
|
marketcap = 0
|
2018-04-11 16:37:30 +00:00
|
|
|
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)
|
2018-04-06 20:11:14 +00:00
|
|
|
details['info']['marketcap_usd'] = marketcap
|
|
|
|
|
2018-04-11 16:37:30 +00:00
|
|
|
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)
|
|
|
|
|
2018-04-06 20:11:14 +00:00
|
|
|
def update_coins(details):
|
|
|
|
coins = json.load(open('coins.json', 'r'))
|
|
|
|
|
2018-04-11 16:37:30 +00:00
|
|
|
supported = []
|
2018-04-06 20:11:14 +00:00
|
|
|
for coin in coins:
|
|
|
|
if coin['firmware'] != 'stable':
|
|
|
|
continue
|
|
|
|
|
2018-04-11 16:37:30 +00:00
|
|
|
# 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'])
|
2018-04-06 20:11:14 +00:00
|
|
|
set_default(out, 'name', coin['coin_label'])
|
2018-04-11 16:37:30 +00:00
|
|
|
set_default(out, 'links', {})
|
2018-04-06 20:11:14 +00:00
|
|
|
set_default(out, 't1_enabled', 'yes')
|
|
|
|
set_default(out, 't2_enabled', 'yes')
|
2018-04-11 16:37:30 +00:00
|
|
|
update_marketcap(out, coin.get('coinmarketcap_alias', coin['coin_label']))
|
2018-04-06 20:11:14 +00:00
|
|
|
|
2018-04-11 16:37:30 +00:00
|
|
|
check_unsupported(details, 'coin:', supported)
|
2018-04-06 20:11:14 +00:00
|
|
|
|
|
|
|
def update_erc20(details):
|
2018-05-23 14:42:08 +00:00
|
|
|
networks = ['eth',
|
|
|
|
'exp',
|
|
|
|
# 'rop',
|
|
|
|
# 'rin',
|
|
|
|
'ubq',
|
|
|
|
# 'rsk',
|
|
|
|
# 'kov',
|
|
|
|
'etc',
|
2018-04-06 21:10:35 +00:00
|
|
|
]
|
|
|
|
|
2018-05-24 14:25:44 +00:00
|
|
|
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'
|
|
|
|
|
2018-05-23 14:42:08 +00:00
|
|
|
tokens = ethereum_tokens_gen.get_tokens()
|
2018-05-24 14:25:44 +00:00
|
|
|
tokens_t1 = requests.get(LATEST_T1).text
|
|
|
|
tokens_t2 = requests.get(LATEST_T2).text
|
|
|
|
|
2018-04-11 16:37:30 +00:00
|
|
|
supported = []
|
2018-05-23 14:42:08 +00:00
|
|
|
for t in tokens:
|
2018-05-25 09:29:37 +00:00
|
|
|
# print('Updating', t['symbol'])
|
2018-04-06 20:11:14 +00:00
|
|
|
|
2018-05-23 14:42:08 +00:00
|
|
|
if t['chain'] not in networks:
|
|
|
|
print('Skipping, %s is disabled' % t['chain'])
|
|
|
|
continue
|
2018-04-06 21:10:35 +00:00
|
|
|
|
2018-05-23 14:42:08 +00:00
|
|
|
key = "erc20:%s:%s" % (t['chain'], t['symbol'])
|
2018-04-11 16:37:30 +00:00
|
|
|
supported.append(key)
|
|
|
|
out = details['coins'].setdefault(key, {})
|
2018-04-06 20:11:14 +00:00
|
|
|
out['type'] = 'erc20'
|
2018-05-23 14:42:08 +00:00
|
|
|
out['network'] = t['chain']
|
|
|
|
out['address'] = t['address']
|
2018-04-11 16:37:30 +00:00
|
|
|
|
2018-05-23 14:42:08 +00:00
|
|
|
set_default(out, 'shortcut', t['symbol'])
|
|
|
|
set_default(out, 'name', t['name'])
|
2018-04-06 21:10:35 +00:00
|
|
|
set_default(out, 'links', {})
|
|
|
|
|
2018-05-25 09:29:37 +00:00
|
|
|
if "\" %s\"" % t['symbol'] in tokens_t1:
|
2018-05-24 14:25:44 +00:00
|
|
|
out['t1_enabled'] = 'yes'
|
|
|
|
else:
|
|
|
|
out['t1_enabled'] = 'soon'
|
|
|
|
|
2018-05-25 09:29:37 +00:00
|
|
|
if "'%s'" % t['symbol'] in tokens_t2:
|
|
|
|
out['t2_enabled'] = 'yes'
|
2018-05-24 14:25:44 +00:00
|
|
|
else:
|
2018-05-25 09:29:37 +00:00
|
|
|
out['t2_enabled'] = 'soon'
|
2018-05-24 14:25:44 +00:00
|
|
|
|
|
|
|
out['links']['MyCrypto Wallet'] = 'https://mycrypto.com'
|
|
|
|
out['links']['MyEtherWallet'] = 'https://www.myetherwallet.com'
|
|
|
|
|
2018-05-23 14:42:08 +00:00
|
|
|
if t['website']:
|
|
|
|
out['links']['Homepage'] = t['website']
|
|
|
|
if t.get('social', {}).get('github', None):
|
|
|
|
out['links']['Github'] = t['social']['github']
|
2018-04-06 20:11:14 +00:00
|
|
|
|
2018-05-23 14:42:08 +00:00
|
|
|
update_marketcap(out, out.get('coinmarketcap_alias', t['symbol']))
|
2018-04-11 16:37:30 +00:00
|
|
|
|
|
|
|
check_unsupported(details, 'erc20:', supported)
|
|
|
|
|
2018-04-06 20:11:14 +00:00
|
|
|
def update_ethereum(details):
|
2018-04-11 16:37:30 +00:00
|
|
|
out = details['coins'].setdefault('coin2:ETH', {})
|
2018-04-06 20:11:14 +00:00
|
|
|
out['type'] = 'coin'
|
2018-04-11 16:37:30 +00:00
|
|
|
set_default(out, 'shortcut', 'ETH')
|
|
|
|
set_default(out, 'name', 'Ethereum')
|
2018-04-06 20:11:14 +00:00
|
|
|
set_default(out, 't1_enabled', 'yes')
|
|
|
|
set_default(out, 't2_enabled', 'yes')
|
|
|
|
update_marketcap(out, 'ethereum')
|
|
|
|
|
2018-04-11 17:30:25 +00:00
|
|
|
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')
|
|
|
|
|
2018-04-11 17:39:04 +00:00
|
|
|
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')
|
|
|
|
|
2018-04-11 17:30:25 +00:00
|
|
|
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')
|
2018-05-16 15:30:28 +00:00
|
|
|
|
2018-05-27 08:19:36 +00:00
|
|
|
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')
|
|
|
|
|
2018-05-09 11:53:55 +00:00
|
|
|
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')
|
2018-04-11 17:30:25 +00:00
|
|
|
|
2018-05-16 15:30:28 +00:00
|
|
|
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')
|
|
|
|
|
2018-06-06 08:16:51 +00:00
|
|
|
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')
|
|
|
|
|
2018-04-06 21:10:35 +00:00
|
|
|
def update_mosaics(details):
|
2018-05-22 17:42:49 +00:00
|
|
|
d = json.load(open('defs/nem/nem_mosaics.json'))
|
2018-04-11 16:37:30 +00:00
|
|
|
supported = []
|
2018-05-22 17:42:49 +00:00
|
|
|
for mosaic in d:
|
2018-04-11 16:37:30 +00:00
|
|
|
# print('Updating', mosaic['name'], mosaic['ticker'])
|
2018-04-06 21:10:35 +00:00
|
|
|
|
2018-04-11 16:37:30 +00:00
|
|
|
key = "mosaic:%s" % mosaic['ticker'].strip()
|
|
|
|
supported.append(key)
|
|
|
|
out = details['coins'].setdefault(key, {})
|
2018-04-06 21:10:35 +00:00
|
|
|
out['type'] = 'mosaic'
|
2018-04-11 16:37:30 +00:00
|
|
|
set_default(out, 'shortcut', mosaic['ticker'].strip())
|
|
|
|
set_default(out, 'name', mosaic['name'])
|
2018-04-06 21:10:35 +00:00
|
|
|
set_default(out, 't1_enabled', 'yes')
|
|
|
|
set_default(out, 't2_enabled', 'yes')
|
|
|
|
|
2018-04-11 16:37:30 +00:00
|
|
|
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]
|
2018-05-25 09:29:37 +00:00
|
|
|
hide = False
|
2018-05-24 14:25:44 +00:00
|
|
|
|
2018-04-11 16:37:30 +00:00
|
|
|
if 'links' not in coin:
|
|
|
|
print("%s: Missing links" % k)
|
2018-05-25 09:29:37 +00:00
|
|
|
hide = True
|
2018-04-11 16:37:30 +00:00
|
|
|
if 'Homepage' not in coin['links']:
|
|
|
|
print("%s: Missing homepage" % k)
|
2018-05-25 09:29:37 +00:00
|
|
|
hide = True
|
2018-05-24 14:25:44 +00:00
|
|
|
if coin['t1_enabled'] not in ('yes', 'no', 'planned', 'soon'):
|
2018-04-11 16:37:30 +00:00
|
|
|
print("%s: Unknown t1_enabled" % k)
|
2018-05-25 09:29:37 +00:00
|
|
|
hide = True
|
2018-05-24 14:25:44 +00:00
|
|
|
if coin['t2_enabled'] not in ('yes', 'no', 'planned', 'soon'):
|
2018-04-11 16:37:30 +00:00
|
|
|
print("%s: Unknown t2_enabled" % k)
|
2018-05-25 09:29:37 +00:00
|
|
|
hide = True
|
2018-04-11 16:37:30 +00:00
|
|
|
if 'TREZOR Wallet' in coin['links'] and coin['links']['TREZOR Wallet'] != 'https://wallet.trezor.io':
|
|
|
|
print("%s: Strange URL for TREZOR Wallet" % k)
|
2018-05-25 09:29:37 +00:00
|
|
|
hide = True
|
2018-04-06 20:11:14 +00:00
|
|
|
|
2018-05-24 14:25:44 +00:00
|
|
|
for w in [ x.lower() for x in coin['links'].keys() ]:
|
2018-05-25 09:29:37 +00:00
|
|
|
if 'wallet' in w or 'electrum' in w:
|
2018-05-24 14:25:44 +00:00
|
|
|
break
|
|
|
|
else:
|
|
|
|
if coin['t1_enabled'] == 'yes' or coin['t2_enabled'] == 'yes':
|
|
|
|
print("%s: Missing wallet" % k)
|
2018-05-25 09:29:37 +00:00
|
|
|
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)
|
2018-05-24 14:25:44 +00:00
|
|
|
|
2018-04-06 20:11:14 +00:00
|
|
|
if __name__ == '__main__':
|
|
|
|
try:
|
|
|
|
details = json.load(open('coins_details.json', 'r'))
|
|
|
|
except FileNotFoundError:
|
|
|
|
details = {'coins': {}, 'info': {}}
|
|
|
|
|
2018-05-22 17:42:49 +00:00
|
|
|
coinmarketcap_init()
|
2018-04-06 20:11:14 +00:00
|
|
|
update_coins(details)
|
2018-05-23 14:42:08 +00:00
|
|
|
update_erc20(details)
|
2018-04-06 20:11:14 +00:00
|
|
|
update_ethereum(details)
|
2018-04-06 21:10:35 +00:00
|
|
|
update_mosaics(details)
|
2018-04-06 20:11:14 +00:00
|
|
|
update_info(details)
|
2018-04-11 16:37:30 +00:00
|
|
|
check_missing_details(details)
|
2018-04-06 20:11:14 +00:00
|
|
|
|
2018-04-11 16:37:30 +00:00
|
|
|
print(json.dumps(details['info'], sort_keys=True, indent=4))
|
2018-04-06 20:11:14 +00:00
|
|
|
json.dump(details, open('coins_details.json', 'w'), sort_keys=True, indent=4)
|