1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-26 09:28:13 +00:00

tools: unified retrieval of coin data, regenerated coins_details

This commit is contained in:
matejcik 2018-07-20 16:49:45 +02:00
parent cebeb81e8c
commit 288445cecc
3 changed files with 775 additions and 945 deletions

File diff suppressed because it is too large Load Diff

404
tools/coin_defs.py Executable file
View File

@ -0,0 +1,404 @@
#!/usr/bin/env python3
from binascii import unhexlify
from collections import defaultdict, OrderedDict
import re
import os
import json
import glob
import logging
try:
import requests
except ImportError:
requests = None
log = logging.getLogger(__name__)
DEFS_DIR = os.path.abspath(
os.environ.get("DEFS_DIR") or os.path.join(os.path.dirname(__file__), "..", "defs")
)
def load_json(*path):
if len(path) == 1 and path[0].startswith("/"):
filename = path[0]
else:
filename = os.path.join(DEFS_DIR, *path)
with open(filename) as f:
return json.load(f, object_pairs_hook=OrderedDict)
# ====== coin validation ======
def check_type(val, types, nullable=False, empty=False, regex=None, choice=None):
# check nullable
if val is None:
if nullable:
return
else:
raise ValueError("Missing required value")
# check type
if not isinstance(val, types):
raise TypeError("Wrong type (expected: {})".format(types))
# check empty
if isinstance(val, (list, dict)) and not empty and not val:
raise ValueError("Empty collection")
# check regex
if regex is not None:
if types is not str:
raise TypeError("Wrong type for regex check")
if not re.search(regex, val):
raise ValueError("Value does not match regex {}".format(regex))
# check choice
if choice is not None and val not in choice:
raise ValueError("Value not allowed, use one of: {}".format(", ".join(choice)))
def check_key(key, types, **kwargs):
def do_check(coin):
if not key in coin:
raise KeyError("{}: Missing key".format(key))
try:
check_type(coin[key], types, **kwargs)
except Exception as e:
raise ValueError("{}: {}".format(key, e)) from e
return do_check
COIN_CHECKS = [
check_key("coin_name", str, regex=r"^[A-Z]"),
check_key("coin_shortcut", str, regex=r"^t?[A-Z]{3,}$"),
check_key("coin_label", str, regex=r"^[A-Z]"),
check_key("website", str, regex=r"^http.*[^/]$"),
check_key("github", str, regex=r"^https://github.com/.*[^/]$"),
check_key("maintainer", str),
check_key(
"curve_name", str, choice=["secp256k1", "secp256k1_decred", "secp256k1_groestl"]
),
check_key("address_type", int),
check_key("address_type_p2sh", int),
check_key("maxfee_kb", int),
check_key("minfee_kb", int),
check_key("hash_genesis_block", str, regex=r"^[0-9a-f]{64}$"),
check_key("xprv_magic", int),
check_key("xpub_magic", int),
check_key("xpub_magic_segwit_p2sh", int, nullable=True),
check_key("xpub_magic_segwit_native", int, nullable=True),
check_key("slip44", int),
check_key("segwit", bool),
check_key("decred", bool),
check_key("fork_id", int, nullable=True),
check_key("force_bip143", bool),
check_key("bip115", bool),
check_key("version_group_id", int, nullable=True),
check_key("default_fee_b", dict),
check_key("dust_limit", int),
check_key("blocktime_seconds", int),
check_key("signed_message_header", str),
check_key("address_prefix", str, regex=r":$"),
check_key("min_address_length", int),
check_key("max_address_length", int),
check_key("bech32_prefix", str, nullable=True),
check_key("cashaddr_prefix", str, nullable=True),
check_key("bitcore", list, empty=True),
check_key("blockbook", list, empty=True),
]
def validate_coin(coin):
errors = []
for check in COIN_CHECKS:
try:
check(coin)
except Exception as e:
errors.append(str(e))
magics = [
coin[k]
for k in (
"xprv_magic",
"xpub_magic",
"xpub_magic_segwit_p2sh",
"xpub_magic_segwit_native",
)
if coin[k] is not None
]
# each of those must be unique
# therefore length of list == length of set of unique values
if len(magics) != len(set(magics)):
errors.append("XPUB/XPRV magic numbers must be unique")
if coin["address_type"] == coin["address_type_p2sh"]:
errors.append("address_type must be distinct from address_type_p2sh")
if not coin["maxfee_kb"] >= coin["minfee_kb"]:
errors.append("max fee must not be smaller than min fee")
if not coin["max_address_length"] >= coin["min_address_length"]:
errors.append("max address length must not be smaller than min address length")
for bc in coin["bitcore"] + coin["blockbook"]:
if bc.endswith("/"):
errors.append("make sure URLs don't end with '/'")
return errors
# ======= Coin json loaders =======
def get_coins():
coins = []
for filename in glob.glob(os.path.join(DEFS_DIR, "coins", "*.json")):
coin = load_json(filename)
coin.update(
name=coin["coin_name"],
shortcut=coin["coin_shortcut"],
key="btc:{}".format(coin["coin_shortcut"]),
)
coins.append(coin)
return coins
def get_ethereum_networks():
networks = load_json("ethereum", "networks.json")
for network in networks:
network.update(key="eth:{}".format(network["shortcut"]))
return networks
def get_erc20_tokens():
networks = get_ethereum_networks()
tokens = []
for network in networks:
if network["name"].startswith("Ethereum Testnet "):
idx = len("Ethereum Testnet ")
chain = network["name"][idx : idx + 3]
else:
chain = network["shortcut"]
chain = chain.lower()
if not chain:
continue
chain_path = os.path.join(DEFS_DIR, "ethereum", "tokens", "tokens", chain)
for filename in glob.glob(os.path.join(chain_path, "*.json")):
token = load_json(filename)
token.update(
chain=chain,
chain_id=network["chain_id"],
address_bytes=unhexlify(token["address"][2:]),
shortcut=token["symbol"],
key="erc20:{}:{}".format(chain, token["symbol"]),
)
tokens.append(token)
return tokens
def get_nem_mosaics():
mosaics = load_json("nem", "nem_mosaics.json")
for mosaic in mosaics:
shortcut = mosaic["ticker"].strip()
mosaic.update(shortcut=shortcut, key="nem:{}".format(shortcut))
return mosaics
def get_others():
others = load_json("others.json")
for other in others:
other.update(key="network:{}".format(other["shortcut"]))
return others
# ====== support info ======
RELEASES_URL = "https://wallet.trezor.io/data/firmware/{}/releases.json"
ETHEREUM_TOKENS = {
"1": "https://raw.githubusercontent.com/trezor/trezor-mcu/v{}/firmware/ethereum_tokens.c",
"2": "https://raw.githubusercontent.com/trezor/trezor-core/v{}/src/apps/ethereum/tokens.py",
}
TOKEN_MATCH = {
"1": re.compile(r'\{.*" ([^"]+)".*\},'),
"2": re.compile(r'\(.*["\']([^"\']+)["\'].*\),'),
}
def latest_releases():
if not requests:
raise RuntimeError("requests library is required for getting release info")
latest = {}
for v in ("1", "2"):
releases = requests.get(RELEASES_URL.format(v)).json()
latest[v] = max(tuple(r["version"]) for r in releases)
return latest
def support_info_erc20(coins, versions):
supported_tokens = {}
for trezor, version in versions.items():
tokens = set()
version_str = ".".join(map(str, version))
token_file = requests.get(ETHEREUM_TOKENS[trezor].format(version_str)).text
token_match = TOKEN_MATCH[trezor]
for line in token_file.split("\n"):
m = token_match.search(line)
if m:
tokens.add(m.group(1))
supported_tokens[trezor] = tokens
support = {}
for coin in coins:
key = coin["key"]
if not key.startswith("erc20:"):
continue
support[key] = dict(
trezor1="yes" if coin["shortcut"] in supported_tokens["1"] else "soon",
trezor2="yes" if coin["shortcut"] in supported_tokens["2"] else "soon",
)
return support
def support_info(coins, erc20_versions=None):
support_data = load_json("support.json")
support = {}
for coin in coins:
key = coin["key"]
typ = key.split(":", maxsplit=1)[0]
if key in support_data:
support[key] = support_data[key]
elif typ in ("nem", "eth"):
support[key] = dict(trezor1="yes", trezor2="yes")
elif typ == "erc20":
# you must call a separate function to get that
continue
else:
log.warning("support info missing for {}".format(key))
support[key] = {}
if erc20_versions:
erc20 = support_info_erc20(coins, erc20_versions)
erc20.update(support)
return erc20
else:
return support
# ====== data cleanup functions ======
def find_address_collisions(coins):
slip44 = defaultdict(list)
at_p2pkh = defaultdict(list)
at_p2sh = defaultdict(list)
for name, coin in coins.items():
s = coin["slip44"]
# ignore m/1 testnets
if not (name.endswith("Testnet") and s == 1):
slip44[s].append(s)
# skip address types on cashaddr currencies
if coin["cashaddr_prefix"]:
continue
at_p2pkh[coin["address_type"]].append(name)
at_p2sh[coin["address_type_p2sh"]].append(name)
def prune(d):
ret = d.copy()
for key in d.keys():
if len(d[key]) < 2:
del ret[key]
return ret
return dict(
slip44=prune(slip44),
address_type=prune(at_p2pkh),
address_type_p2sh=prune(at_p2sh),
)
def ensure_mandatory_values(coins):
for coin in coins:
if not all(coin.get(k) for k in ("name", "shortcut", "key")):
raise ValueError(coin)
def filter_duplicate_shortcuts(coins):
dup_keys = set()
retained_coins = OrderedDict()
for coin in coins:
key = coin["shortcut"]
if key in dup_keys:
pass
elif key in retained_coins:
dup_keys.add(key)
del retained_coins[key]
else:
retained_coins[key] = coin
# modify original list
coins[:] = retained_coins.values()
# return duplicates
return dup_keys
def _btc_sort_key(coin):
if coin["name"] in ("Bitcoin", "Testnet"):
return "000000" + coin["name"]
else:
return coin["name"]
def get_all():
all_coins = dict(
btc=get_coins(),
eth=get_ethereum_networks(),
erc20=get_erc20_tokens(),
nem=get_nem_mosaics(),
other=get_others(),
)
for k, coins in all_coins.items():
if k == "btc":
coins.sort(key=_btc_sort_key)
else:
coins.sort(key=lambda c: c["key"].upper())
ensure_mandatory_values(coins)
if k != "eth":
dup_keys = filter_duplicate_shortcuts(coins)
if dup_keys:
log.warning(
"{}: removing duplicate symbols: {}".format(k, ", ".join(dup_keys))
)
return all_coins
def get_list():
all_coins = get_all()
return sum(all_coins.values(), [])
def get_dict():
return {coin["key"]: coin for coin in get_list()}

View File

@ -2,360 +2,343 @@
"""Fetch information about coins and tokens supported by Trezor and update it in coins_details.json."""
import time
import json
import logging
import requests
import ethereum_tokens_gen
import build_coins
from distutils.version import LooseVersion
import coin_defs
T1_LATEST='1.6.2'
T2_LATEST='2.0.7'
OPTIONAL_KEYS = ("links", "notes", "wallet")
OVERRIDES = coin_defs.load_json("coins_details.override.json")
VERSIONS = coin_defs.latest_releases()
COINS = {}
log = logging.getLogger(__name__)
def coinmarketcap_init():
global COINS
try:
COINS = json.load(open('coinmarketcap.json', 'r'))
marketcap_json = 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
pass
# if COINS["1"]["last_updated"] > time.time() - 3600:
# print("Using local cache of coinmarketcap")
# return
for coin in marketcap_json.values():
slug = coin["website_slug"]
market_cap = coin["quotes"]["USD"]["market_cap"]
if market_cap is not None:
COINS[slug] = int(float(market_cap))
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))
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'])
COINS.update(data["data"])
if total is None:
total = data['metadata']['num_cryptocurrencies']
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)
json.dump(COINS, open("coinmarketcap.json", "w"), sort_keys=True, indent=4)
def coinmarketcap_info(shortcut):
global COINS
shortcut = shortcut.replace(' ', '-').lower()
def marketcap(coin):
cap = None
for _id in COINS:
coin = COINS[_id]
# print(shortcut, coin['website_slug'])
if shortcut == coin['website_slug']:
# print(coin)
return coin
if "coinmarketcap_alias" in coin:
cap = COINS.get(coin["coinmarketcap_alias"])
if not cap:
slug = coin["name"].replace(" ", "-").lower()
cap = COINS.get(slug)
if not cap:
cap = COINS.get(coin["shortcut"].lower())
return cap
def update_marketcap(obj, *shortcuts):
for sym in shortcuts:
try:
obj['marketcap_usd'] = int(float(coinmarketcap_info(sym)['quotes']['USD']['market_cap']))
return
except:
pass
# print("Marketcap info not found for", shortcut)
def update_marketcap(coins):
for coin in coins.values():
cap = marketcap(coin)
if cap:
coin["marketcap_usd"] = cap
def coinmarketcap_global():
url = 'https://api.coinmarketcap.com/v2/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"]["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.get('t1_enabled') == 'yes' and not c.get('hidden', False)])
details['info']['t2_coins'] = len([True for _, c in details['coins'].items() if c.get('t2_enabled') == 'yes' and not c.get('hidden', False)])
details["info"]["t1_coins"] = len(
[
True
for _, c in details["coins"].items()
if c.get("t1_enabled") == "yes" and not c.get("hidden", False)
]
)
details["info"]["t2_coins"] = len(
[
True
for _, c in details["coins"].items()
if c.get("t2_enabled") == "yes" and not c.get("hidden", False)
]
)
try:
details['info']['total_marketcap_usd'] = int(coinmarketcap_global()['data']['quotes']['USD']['total_market_cap'])
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
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():
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, _) = build_coins.process(None)
firmware = json.load(open('../defs/support.json', 'r'))
def _is_supported(support, trezor_version):
version = VERSIONS[str(trezor_version)]
nominal = support.get("trezor" + str(trezor_version))
if nominal is None:
return "no"
elif isinstance(nominal, bool):
return "yes" if nominal else "no"
supported = []
for key, coin in coins.items():
t1_enabled = 'no'
if key in firmware['trezor1']:
if LooseVersion(firmware['trezor1'][key]) <= LooseVersion(T1_LATEST):
t1_enabled = 'yes'
else:
t1_enabled = 'soon'
t2_enabled = 'no'
if key in firmware['trezor2']:
if LooseVersion(firmware['trezor2'][key]) <= LooseVersion(T2_LATEST):
t2_enabled = 'yes'
else:
t2_enabled = 'soon'
# 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'
out['t1_enabled'] = t1_enabled
out['t2_enabled'] = t2_enabled
set_default(out, 'shortcut', coin['coin_shortcut'])
set_default(out, 'name', coin['coin_label'])
set_default(out, 'links', {})
set_default(out['links'], 'Homepage', coin['website'])
set_default(out['links'], 'Github', coin['github'])
set_default(out, 'wallet', {})
update_marketcap(out, coin.get('coinmarketcap_alias', coin['coin_label']))
check_unsupported(details, 'coin:', supported)
try:
nominal_version = tuple(map(int, nominal.split(".")))
return "yes" if nominal_version <= version else "soon"
except ValueError:
return nominal
def update_erc20(details):
networks = [x[0] for x in ethereum_tokens_gen.networks]
def _webwallet_support(coin, support):
"""Check the "webwallet" support property.
If set, check that at least one of the backends run on trezor.io.
If yes, assume we support the coin in our wallet.
Otherwise it's probably working with a custom backend, which means don't
link to our wallet.
"""
if not support.get("webwallet"):
return False
return any(".trezor.io" in url for url in coin["blockbook"] + coin["bitcore"])
LATEST_T1 = 'https://raw.githubusercontent.com/trezor/trezor-mcu/v%s/firmware/ethereum_tokens.c' % T1_LATEST
LATEST_T2 = 'https://raw.githubusercontent.com/trezor/trezor-core/v%s/src/apps/ethereum/tokens.py' % T2_LATEST
tokens = ethereum_tokens_gen.get_tokens()
tokens_t1 = requests.get(LATEST_T1).text
tokens_t2 = requests.get(LATEST_T2).text
def update_coins(coins, support_info):
res = {}
for coin in coins:
key = coin["key"]
support = support_info[key]
details = dict(
type="coin",
shortcut=coin["shortcut"],
name=coin["coin_label"],
links=dict(Homepage=coin["website"], Github=coin["github"]),
t1_enabled=_is_supported(support, 1),
t2_enabled=_is_supported(support, 2),
wallet={},
)
if _webwallet_support(coin, support):
details["wallet"]["Trezor"] = "https://wallet.trezor.io"
if support.get("other"):
details["wallet"].update(support["other"])
supported = []
for t in tokens:
# print('Updating', t['symbol'])
# XXX get rid of this in favor of res[key]
res["coin:{}".format(coin["shortcut"])] = details
if t['chain'] not in networks:
print('Skipping, %s is disabled' % t['chain'])
continue
return res
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', {})
set_default(out, 'wallet', {})
def update_erc20(coins, support_info):
# TODO skip disabled networks?
res = {}
for coin in coins:
key = coin["key"]
support = support_info[key]
details = dict(
type="erc20",
network=coin["chain"],
address=coin["address"],
shortcut=coin["shortcut"],
name=coin["name"],
links={},
wallet=dict(
MyCrypto="https://mycrypto.com",
MyEtherWallet="https://www.myetherwallet.com",
),
t1_enabled=support["trezor1"],
t2_enabled=support["trezor2"],
)
if coin.get("website"):
details["links"]["Homepage"] = coin["website"]
if coin.get("social", {}).get("github"):
details["links"]["Github"] = coin["social"]["github"]
if "\" %s\"" % t['symbol'] in tokens_t1:
out['t1_enabled'] = 'yes'
res[key] = details
return res
def update_simple(coins, support_info, type):
res = {}
for coin in coins:
key = coin["key"]
support = support_info[key]
# XXX drop newkey
if type == "mosaic":
newkey = "mosaic:{}".format(coin["shortcut"])
else:
out['t1_enabled'] = 'soon'
newkey = "coin2:{}".format(coin["shortcut"])
if "'%s'" % t['symbol'] in tokens_t2:
out['t2_enabled'] = 'yes'
else:
out['t2_enabled'] = 'soon'
details = dict(
name=coin["name"],
shortcut=coin["shortcut"],
type=type,
t1_enabled=_is_supported(support, 1),
t2_enabled=_is_supported(support, 2),
)
for key in OPTIONAL_KEYS:
if key in coin:
details[key] = coin[key]
out['wallet']['MyCrypto'] = 'https://mycrypto.com'
out['wallet']['MyEtherWallet'] = 'https://www.myetherwallet.com'
res[newkey] = details
if t.get('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['name'], t['symbol'])
check_unsupported(details, 'erc20:', supported)
return res
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', 'Ethereum Social')
set_default(out, 't1_enabled', 'yes')
set_default(out, 't2_enabled', 'yes')
update_marketcap(out, 'etsc')
out = 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')
out = details['coins'].setdefault('coin2:ADA', {})
out['type'] = 'coin'
set_default(out, 'shortcut', 'ADA')
set_default(out, 'name', 'Cardano')
set_default(out, 't1_enabled', 'no')
set_default(out, 't2_enabled', 'soon')
update_marketcap(out, 'cardano')
out = details['coins'].setdefault('coin2:XTZ', {})
out['type'] = 'coin'
set_default(out, 'shortcut', 'XTZ')
set_default(out, 'name', 'Tezos')
set_default(out, 't1_enabled', 'no')
set_default(out, 't2_enabled', 'soon')
update_marketcap(out, 'tezos')
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 update_ethereum_networks(coins, support_info):
res = update_simple(coins, support_info, "coin")
for coin in coins:
newkey = "coin2:{}".format(coin["shortcut"])
res[newkey]["wallet"] = dict(
MyCrypto="https://mycrypto.com",
MyEtherWallet="https://www.myetherwallet.com",
)
res[newkey]["links"] = dict(Homepage=coin.get("url"))
return res
def check_missing_details(details):
for k in details['coins'].keys():
coin = details['coins'][k]
for k in details["coins"].keys():
coin = details["coins"][k]
hide = False
if 'links' not in coin:
if "links" not in coin:
print("%s: Missing links" % k)
hide = True
if 'Homepage' not in coin.get('links', {}):
if "Homepage" not in coin.get("links", {}):
print("%s: Missing homepage" % k)
hide = True
if coin['t1_enabled'] not in ('yes', 'no', 'planned', 'soon'):
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'):
if coin["t2_enabled"] not in ("yes", "no", "planned", "soon"):
print("%s: Unknown t2_enabled" % k)
hide = True
if 'Trezor' in coin.get('wallet', {}) and coin['wallet']['Trezor'] != 'https://wallet.trezor.io':
if (
"Trezor" in coin.get("wallet", {})
and coin["wallet"]["Trezor"] != "https://wallet.trezor.io"
):
print("%s: Strange URL for Trezor Wallet" % k)
hide = True
if len(coin.get('wallet', {})) == 0:
if len(coin.get("wallet", {})) == 0:
print("%s: Missing wallet" % k)
if "Testnet" in coin["name"]:
print("%s: Hiding testnet" % k)
hide = True
if hide:
if coin.get('hidden') != 1:
if coin.get("hidden") != 1:
print("%s: HIDING COIN!" % k)
# If any of important detail is missing, hide coin from list
coin['hidden'] = 1
coin["hidden"] = 1
if not hide and coin.get('hidden'):
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:
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('../defs/coins_details.json', 'r'))
except FileNotFoundError:
details = {'coins': {}, 'info': {}}
def apply_overrides(coins):
for key, override in OVERRIDES.items():
if key not in coins:
log.warning("override without coin: {}".format(key))
continue
def recursive_update(orig, new):
if isinstance(new, dict) and isinstance(orig, dict):
for k, v in new.items():
orig[k] = recursive_update(orig.get(k), v)
else:
return new
coin = coins[key]
recursive_update(coin, override)
if __name__ == "__main__":
# try:
# details = json.load(open('../defs/coins_details.json', 'r'))
# except FileNotFoundError:
# details = {'coins': {}, 'info': {}}
coinmarketcap_init()
update_coins(details)
update_erc20(details)
update_ethereum(details)
update_mosaics(details)
defs = coin_defs.get_all()
all_coins = sum(defs.values(), [])
support_info = coin_defs.support_info(all_coins, erc20_versions=VERSIONS)
coins = {}
coins.update(update_coins(defs["btc"], support_info))
coins.update(update_erc20(defs["erc20"], support_info))
coins.update(update_ethereum_networks(defs["eth"], support_info))
coins.update(update_simple(defs["nem"], support_info, "mosaic"))
coins.update(update_simple(defs["other"], support_info, "coin"))
apply_overrides(coins)
update_marketcap(coins)
details = dict(coins=coins, info={})
update_info(details)
check_missing_details(details)
print(json.dumps(details['info'], sort_keys=True, indent=4))
json.dump(details, open('../defs/coins_details.json', 'w'), sort_keys=True, indent=4)
print(json.dumps(details["info"], sort_keys=True, indent=4))
json.dump(details, open("../defs/coins_details.json", "w"), sort_keys=True, indent=4)