From 80f8f7900db9dcfbb7a226f4b930cceb3551f806 Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Sun, 23 Jun 2019 12:18:59 +0200 Subject: [PATCH] core: add slip39 support to reset and recovery device --- core/mocks/generated/trezorcrypto/slip39.py | 35 ++ core/src/apps/cardano/seed.py | 8 +- core/src/apps/common/confirm.py | 12 +- core/src/apps/common/mnemonic.py | 56 --- core/src/apps/common/mnemonic/__init__.py | 59 +++ core/src/apps/common/mnemonic/bip39.py | 36 ++ core/src/apps/common/mnemonic/slip39.py | 87 ++++ core/src/apps/common/storage.py | 122 ++++- core/src/apps/homescreen/homescreen.py | 42 +- core/src/apps/management/backup_device.py | 24 +- core/src/apps/management/common/layout.py | 519 ++++++++++++++++++++ core/src/apps/management/load_device.py | 10 +- core/src/apps/management/recovery_device.py | 150 +++--- core/src/apps/management/reset_device.py | 247 ++++------ core/src/trezor/crypto/slip39.py | 161 +++--- core/src/trezor/crypto/slip39_wordlist.py | 1 - core/src/trezor/messages/ResetDevice.py | 3 + core/src/trezor/ui/checklist.py | 55 +++ core/src/trezor/ui/confirm.py | 5 + core/src/trezor/ui/info.py | 63 +++ core/src/trezor/ui/loader.py | 20 + core/src/trezor/ui/shamir.py | 49 ++ core/src/trezor/ui/text.py | 78 ++- core/src/trezor/ui/word_select.py | 20 +- core/tests/test_trezor.crypto.slip39.py | 42 +- python/trezorlib/coins.json | 2 +- python/trezorlib/messages/ResetDevice.py | 3 + 27 files changed, 1448 insertions(+), 461 deletions(-) create mode 100644 core/mocks/generated/trezorcrypto/slip39.py delete mode 100644 core/src/apps/common/mnemonic.py create mode 100644 core/src/apps/common/mnemonic/__init__.py create mode 100644 core/src/apps/common/mnemonic/bip39.py create mode 100644 core/src/apps/common/mnemonic/slip39.py create mode 100644 core/src/apps/management/common/layout.py delete mode 100644 core/src/trezor/crypto/slip39_wordlist.py create mode 100644 core/src/trezor/ui/checklist.py create mode 100644 core/src/trezor/ui/info.py create mode 100644 core/src/trezor/ui/shamir.py diff --git a/core/mocks/generated/trezorcrypto/slip39.py b/core/mocks/generated/trezorcrypto/slip39.py new file mode 100644 index 0000000000..056be93f59 --- /dev/null +++ b/core/mocks/generated/trezorcrypto/slip39.py @@ -0,0 +1,35 @@ +from typing import * + + +# extmod/modtrezorcrypto/modtrezorcrypto-slip39.h +def compute_mask(prefix: int) -> int: + """ + Calculates which buttons still can be pressed after some already were. + Returns a 9-bit bitmask, where each bit specifies which buttons + can be further pressed (there are still words in this combination). + LSB denotes first button. + Example: 110000110 - second, third, eighth and ninth button still can be + pressed. + """ + + +# extmod/modtrezorcrypto/modtrezorcrypto-slip39.h +def button_sequence_to_word(prefix: int) -> str: + """ + Finds the first word that fits the given button prefix. + """ + + +# extmod/modtrezorcrypto/modtrezorcrypto-slip39.h +def word_index(word: str) -> int: + """ + Finds index of given word. + Raises ValueError if not found. + """ + + +# extmod/modtrezorcrypto/modtrezorcrypto-slip39.h +def get_word(index: int) -> str: + """ + Returns word on position 'index'. + """ diff --git a/core/src/apps/cardano/seed.py b/core/src/apps/cardano/seed.py index f8efa24b49..d914b53125 100644 --- a/core/src/apps/cardano/seed.py +++ b/core/src/apps/cardano/seed.py @@ -37,7 +37,13 @@ async def get_keychain(ctx: wire.Context) -> Keychain: if passphrase is None: passphrase = await protect_by_passphrase(ctx) cache.set_passphrase(passphrase) - root = bip32.from_mnemonic_cardano(mnemonic.restore(), passphrase) + # TODO fix for SLIP-39! + mnemonic_secret, mnemonic_type = mnemonic.get() + if mnemonic_type == mnemonic.TYPE_SLIP39: + # TODO: we need to modify bip32.from_mnemonic_cardano to accept entropy directly + raise NotImplementedError("SLIP-39 currently does not support Cardano") + else: + root = bip32.from_mnemonic_cardano(mnemonic_secret.decode(), passphrase) # derive the namespaced root node for i in SEED_NAMESPACE: diff --git a/core/src/apps/common/confirm.py b/core/src/apps/common/confirm.py index 9f3b5e50c6..280f3a0e10 100644 --- a/core/src/apps/common/confirm.py +++ b/core/src/apps/common/confirm.py @@ -15,16 +15,24 @@ async def confirm( confirm_style=Confirm.DEFAULT_CONFIRM_STYLE, cancel=Confirm.DEFAULT_CANCEL, cancel_style=Confirm.DEFAULT_CANCEL_STYLE, + major_confirm=None, ): await ctx.call(ButtonRequest(code=code), MessageType.ButtonAck) if content.__class__.__name__ == "Paginated": content.pages[-1] = Confirm( - content.pages[-1], confirm, confirm_style, cancel, cancel_style + content.pages[-1], + confirm, + confirm_style, + cancel, + cancel_style, + major_confirm, ) dialog = content else: - dialog = Confirm(content, confirm, confirm_style, cancel, cancel_style) + dialog = Confirm( + content, confirm, confirm_style, cancel, cancel_style, major_confirm + ) if __debug__: return await ctx.wait(dialog, confirm_signal) is CONFIRMED diff --git a/core/src/apps/common/mnemonic.py b/core/src/apps/common/mnemonic.py deleted file mode 100644 index 22f60f62bb..0000000000 --- a/core/src/apps/common/mnemonic.py +++ /dev/null @@ -1,56 +0,0 @@ -from trezor import ui, workflow -from trezor.crypto import bip39 - -from apps.common import storage - -TYPE_BIP39 = 0 - - -def get() -> (bytes, int): - mnemonic_secret = storage.get_mnemonic_secret() - mnemonic_type = storage.get_mnemonic_type() or TYPE_BIP39 - return mnemonic_secret, mnemonic_type - - -def get_seed(passphrase: str = "", progress_bar=True): - secret, mnemonic_type = get() - if mnemonic_type == TYPE_BIP39: - module = bip39 - if progress_bar: - _start_progress() - result = module.seed(secret.decode(), passphrase, _render_progress) - _stop_progress() - else: - result = module.seed(secret.decode(), passphrase) - return result - - -def process(mnemonics: list, mnemonic_type: int): - if mnemonic_type == TYPE_BIP39: - return mnemonics[0].encode() - else: - raise RuntimeError("Unknown mnemonic type") - - -def restore() -> str: - secret, mnemonic_type = get() - if mnemonic_type == TYPE_BIP39: - return secret.decode() - - -def _start_progress(): - ui.backlight_fade(ui.BACKLIGHT_DIM) - ui.display.clear() - ui.header("Please wait") - ui.display.refresh() - ui.backlight_fade(ui.BACKLIGHT_NORMAL) - - -def _render_progress(progress: int, total: int): - p = 1000 * progress // total - ui.display.loader(p, False, 18, ui.WHITE, ui.BG) - ui.display.refresh() - - -def _stop_progress(): - workflow.restartdefault() diff --git a/core/src/apps/common/mnemonic/__init__.py b/core/src/apps/common/mnemonic/__init__.py new file mode 100644 index 0000000000..b729bb3a3f --- /dev/null +++ b/core/src/apps/common/mnemonic/__init__.py @@ -0,0 +1,59 @@ +from micropython import const + +from trezor import ui, wire +from trezor.crypto.hashlib import sha256 +from trezor.messages.Success import Success +from trezor.utils import consteq + +from . import bip39, slip39 + +from apps.common import storage + +TYPE_BIP39 = const(0) +TYPE_SLIP39 = const(1) + +TYPES_WORD_COUNT = {12: bip39, 18: bip39, 24: bip39, 20: slip39, 33: slip39} + + +def get() -> (bytes, int): + mnemonic_secret = storage.get_mnemonic_secret() + mnemonic_type = storage.get_mnemonic_type() or TYPE_BIP39 + return mnemonic_secret, mnemonic_type + + +def get_seed(passphrase: str = ""): + mnemonic_secret, mnemonic_type = get() + if mnemonic_type == TYPE_BIP39: + return bip39.get_seed(mnemonic_secret, passphrase) + elif mnemonic_type == TYPE_SLIP39: + return slip39.get_seed(mnemonic_secret, passphrase) + + +def dry_run(secret: bytes): + digest_input = sha256(secret).digest() + stored, _ = get() + digest_stored = sha256(stored).digest() + if consteq(digest_stored, digest_input): + return Success(message="The seed is valid and matches the one in the device") + else: + raise wire.ProcessError( + "The seed is valid but does not match the one in the device" + ) + + +def module_from_words_count(count: int): + return TYPES_WORD_COUNT[count] + + +def _start_progress(): + ui.backlight_fade(ui.BACKLIGHT_DIM) + ui.display.clear() + ui.header("Please wait") + ui.display.refresh() + ui.backlight_fade(ui.BACKLIGHT_NORMAL) + + +def _render_progress(progress: int, total: int): + p = 1000 * progress // total + ui.display.loader(p, False, 18, ui.WHITE, ui.BG) + ui.display.refresh() diff --git a/core/src/apps/common/mnemonic/bip39.py b/core/src/apps/common/mnemonic/bip39.py new file mode 100644 index 0000000000..81ac429675 --- /dev/null +++ b/core/src/apps/common/mnemonic/bip39.py @@ -0,0 +1,36 @@ +from trezor.crypto import bip39 + +from apps.common import mnemonic, storage + + +def get_type(): + return mnemonic.TYPE_BIP39 + + +def process_single(mnemonic: str) -> bytes: + """ + Receives single mnemonic and processes it. Returns what is then stored in storage or + None if more shares are needed. + """ + return mnemonic.encode() + + +def process_all(mnemonics: list) -> bytes: + """ + Receives all mnemonics (just one in case of BIP-39) and processes it into a master + secret which is usually then stored in storage. + """ + return mnemonics[0].encode() + + +def store(secret: bytes, needs_backup: bool, no_backup: bool): + storage.store_mnemonic(secret, mnemonic.TYPE_BIP39, needs_backup, no_backup) + + +def get_seed(secret: bytes, passphrase: str): + mnemonic._start_progress() + return bip39.seed(secret.decode(), passphrase, mnemonic._render_progress) + + +def check(secret: bytes): + return bip39.check(secret) diff --git a/core/src/apps/common/mnemonic/slip39.py b/core/src/apps/common/mnemonic/slip39.py new file mode 100644 index 0000000000..040f79aef6 --- /dev/null +++ b/core/src/apps/common/mnemonic/slip39.py @@ -0,0 +1,87 @@ +from trezor.crypto import slip39 + +from apps.common import mnemonic, storage + + +def generate_from_secret(master_secret: bytes, count: int, threshold: int) -> str: + """ + Generates new Shamir backup for 'master_secret'. Multiple groups are not yet supported. + """ + identifier, group_mnemonics = slip39.generate_single_group_mnemonics_from_data( + master_secret, threshold, count + ) + storage.set_slip39_iteration_exponent(slip39.DEFAULT_ITERATION_EXPONENT) + storage.set_slip39_identifier(identifier) + return group_mnemonics + + +def get_type(): + return mnemonic.TYPE_SLIP39 + + +def process_single(mnemonic: str) -> bytes: + """ + Receives single mnemonic and processes it. Returns what is then stored in storage or + None if more shares are needed. + """ + identifier, iteration_exponent, _, _, _, index, threshold, value = slip39.decode_mnemonic( + mnemonic + ) # TODO: use better data structure for this + if threshold == 1: + raise ValueError("Threshold equal to 1 is not allowed.") + + # if recovery is not in progress already, start it and wait for more mnemonics + if not storage.is_slip39_in_progress(): + storage.set_slip39_in_progress(True) + storage.set_slip39_iteration_exponent(iteration_exponent) + storage.set_slip39_identifier(identifier) + storage.set_slip39_threshold(threshold) + storage.set_slip39_remaining(threshold - 1) + storage.set_slip39_words_count(len(mnemonic.split())) + storage.set_slip39_mnemonic(index, mnemonic) + return None # we need more shares + + # check identifier and member index of this share against stored values + if identifier != storage.get_slip39_identifier(): + # TODO: improve UX (tell user) + raise ValueError("Share identifiers do not match") + if storage.get_slip39_mnemonic(index): + # TODO: improve UX (tell user) + raise ValueError("This mnemonic was already entered") + + # append to storage + remaining = storage.get_slip39_remaining() - 1 + storage.set_slip39_remaining(remaining) + storage.set_slip39_mnemonic(index, mnemonic) + if remaining != 0: + return None # we need more shares + + # combine shares and return the master secret + mnemonics = storage.get_slip39_mnemonics() + if len(mnemonics) != threshold: + raise ValueError("Some mnemonics are still missing.") + _, _, secret = slip39.combine_mnemonics(mnemonics) + return secret + + +def process_all(mnemonics: list) -> bytes: + """ + Receives all mnemonics and processes it into pre-master secret which is usually then + stored in the storage. + """ + _, _, secret = slip39.combine_mnemonics(mnemonics) + return secret + + +def store(secret: bytes, needs_backup: bool, no_backup: bool): + storage.store_mnemonic(secret, mnemonic.TYPE_SLIP39, needs_backup, no_backup) + storage.clear_slip39_data() + + +def get_seed(encrypted_master_secret: bytes, passphrase: str): + mnemonic._start_progress() + identifier = storage.get_slip39_identifier() + iteration_exponent = storage.get_slip39_iteration_exponent() + return slip39.decrypt( + identifier, iteration_exponent, encrypted_master_secret, passphrase + ) diff --git a/core/src/apps/common/storage.py b/core/src/apps/common/storage.py index ec5e551739..0974c67b1e 100644 --- a/core/src/apps/common/storage.py +++ b/core/src/apps/common/storage.py @@ -2,7 +2,7 @@ from micropython import const from ubinascii import hexlify from trezor import config -from trezor.crypto import random +from trezor.crypto import random, slip39 from apps.common import cache @@ -32,9 +32,100 @@ _AUTOLOCK_DELAY_MS = const(0x0C) # int _NO_BACKUP = const(0x0D) # bool (0x01 or empty) _MNEMONIC_TYPE = const(0x0E) # int _ROTATION = const(0x0F) # int + +_SLIP39 = const(0x02) # SLIP-39 namespace +_SLIP39_IN_PROGRESS = const(0x00) # bool +_SLIP39_IDENTIFIER = const(0x01) # bytes +_SLIP39_THRESHOLD = const(0x02) # int +_SLIP39_REMAINING = const(0x03) # int +_SLIP39_WORDS_COUNT = const(0x04) # int +_SLIP39_ITERATION_EXPONENT = const(0x05) # int + +# Mnemonics stored during SLIP-39 recovery process. +# Each mnemonic is stored under key = index. +_SLIP39_MNEMONICS = const(0x03) # SLIP-39 mnemonics namespace + # fmt: on +def set_slip39_in_progress(val: bool): + _set_bool(_SLIP39, _SLIP39_IN_PROGRESS, val) + + +def is_slip39_in_progress(): + return _get_bool(_SLIP39, _SLIP39_IN_PROGRESS) + + +def set_slip39_identifier(identifier: int): + _set_uint16(_SLIP39, _SLIP39_IDENTIFIER, identifier) + + +def get_slip39_identifier() -> int: + return _get_uint16(_SLIP39, _SLIP39_IDENTIFIER) + + +def set_slip39_threshold(threshold: int): + _set_uint8(_SLIP39, _SLIP39_THRESHOLD, threshold) + + +def get_slip39_threshold() -> int: + return _get_uint8(_SLIP39, _SLIP39_THRESHOLD) + + +def set_slip39_remaining(remaining: int): + _set_uint8(_SLIP39, _SLIP39_REMAINING, remaining) + + +def get_slip39_remaining() -> int: + return _get_uint8(_SLIP39, _SLIP39_REMAINING) + + +def set_slip39_words_count(count: int): + _set_uint8(_SLIP39, _SLIP39_WORDS_COUNT, count) + + +def get_slip39_words_count() -> int: + return _get_uint8(_SLIP39, _SLIP39_WORDS_COUNT) + + +def set_slip39_iteration_exponent(exponent: int): + # TODO: check if not > 5 bits + _set_uint8(_SLIP39, _SLIP39_ITERATION_EXPONENT, exponent) + + +def get_slip39_iteration_exponent() -> int: + return _get_uint8(_SLIP39, _SLIP39_ITERATION_EXPONENT) + + +def set_slip39_mnemonic(index: int, mnemonic: str): + config.set(_SLIP39_MNEMONICS, index, mnemonic.encode()) + + +def get_slip39_mnemonic(index: int) -> str: + m = config.get(_SLIP39_MNEMONICS, index) + if m: + return m.decode() + return False + + +def get_slip39_mnemonics() -> list: + mnemonics = [] + for index in range(0, slip39.MAX_SHARE_COUNT): + m = get_slip39_mnemonic(index) + if m: + mnemonics.append(m) + return mnemonics + + +def clear_slip39_data(): + config.delete(_SLIP39, _SLIP39_IN_PROGRESS) + config.delete(_SLIP39, _SLIP39_REMAINING) + config.delete(_SLIP39, _SLIP39_THRESHOLD) + config.delete(_SLIP39, _SLIP39_WORDS_COUNT) + for index in (0, slip39.MAX_SHARE_COUNT): + config.delete(_SLIP39_MNEMONICS, index) + + def _set_bool(app: int, key: int, value: bool, public: bool = False) -> None: if value: config.set(app, key, _TRUE_BYTE, public) @@ -57,6 +148,17 @@ def _get_uint8(app: int, key: int) -> int: return int.from_bytes(val, "big") +def _set_uint16(app: int, key: int, val: int): + config.set(app, key, val.to_bytes(2, "big")) + + +def _get_uint16(app: int, key: int) -> int: + val = config.get(app, key) + if not val: + return None + return int.from_bytes(val, "big") + + def _new_device_id() -> str: return hexlify(random.bytes(12)).decode().upper() @@ -77,7 +179,9 @@ def get_rotation() -> int: def is_initialized() -> bool: - return bool(config.get(_APP, _VERSION)) + return bool(config.get(_APP, _VERSION)) and not bool( + config.get(_SLIP39, _SLIP39_IN_PROGRESS) + ) def get_label() -> str: @@ -88,10 +192,7 @@ def get_label() -> str: def get_mnemonic_secret() -> bytes: - mnemonic = config.get(_APP, _MNEMONIC_SECRET) - if mnemonic is None: - return None - return mnemonic + return config.get(_APP, _MNEMONIC_SECRET) def get_mnemonic_type() -> int: @@ -107,10 +208,17 @@ def get_homescreen() -> bytes: def store_mnemonic( - secret: bytes, mnemonic_type: int, needs_backup: bool, no_backup: bool + secret: bytes, + mnemonic_type: int, + needs_backup: bool = False, + no_backup: bool = False, ) -> None: config.set(_APP, _MNEMONIC_SECRET, secret) _set_uint8(_APP, _MNEMONIC_TYPE, mnemonic_type) + _init(needs_backup, no_backup) + + +def _init(needs_backup=False, no_backup=False): config.set(_APP, _VERSION, _STORAGE_VERSION) _set_bool(_APP, _NO_BACKUP, no_backup) if not no_backup: diff --git a/core/src/apps/homescreen/homescreen.py b/core/src/apps/homescreen/homescreen.py index a89af2e91e..4a229063a0 100644 --- a/core/src/apps/homescreen/homescreen.py +++ b/core/src/apps/homescreen/homescreen.py @@ -16,9 +16,11 @@ async def homescreen(): def display_homescreen(): - if not storage.is_initialized(): + image = None + if storage.is_slip39_in_progress(): + label = "Waiting for other shares" + elif not storage.is_initialized(): label = "Go to trezor.io/start" - image = None else: label = storage.get_label() or "My Trezor" image = storage.get_homescreen() @@ -27,28 +29,28 @@ def display_homescreen(): image = res.load("apps/homescreen/res/bg.toif") if storage.is_initialized() and storage.no_backup(): - ui.display.bar(0, 0, ui.WIDTH, 30, ui.RED) - ui.display.text_center(ui.WIDTH // 2, 22, "SEEDLESS", ui.BOLD, ui.WHITE, ui.RED) - ui.display.bar(0, 30, ui.WIDTH, ui.HEIGHT - 30, ui.BG) + _err("SEEDLESS") elif storage.is_initialized() and storage.unfinished_backup(): - ui.display.bar(0, 0, ui.WIDTH, 30, ui.RED) - ui.display.text_center( - ui.WIDTH // 2, 22, "BACKUP FAILED!", ui.BOLD, ui.WHITE, ui.RED - ) - ui.display.bar(0, 30, ui.WIDTH, ui.HEIGHT - 30, ui.BG) + _err("BACKUP FAILED!") elif storage.is_initialized() and storage.needs_backup(): - ui.display.bar(0, 0, ui.WIDTH, 30, ui.YELLOW) - ui.display.text_center( - ui.WIDTH // 2, 22, "NEEDS BACKUP!", ui.BOLD, ui.BLACK, ui.YELLOW - ) - ui.display.bar(0, 30, ui.WIDTH, ui.HEIGHT - 30, ui.BG) + _warn("NEEDS BACKUP!") elif storage.is_initialized() and not config.has_pin(): - ui.display.bar(0, 0, ui.WIDTH, 30, ui.YELLOW) - ui.display.text_center( - ui.WIDTH // 2, 22, "PIN NOT SET!", ui.BOLD, ui.BLACK, ui.YELLOW - ) - ui.display.bar(0, 30, ui.WIDTH, ui.HEIGHT - 30, ui.BG) + _warn("PIN NOT SET!") + elif storage.is_slip39_in_progress(): + _warn("SHAMIR IN PROGRESS!") else: ui.display.bar(0, 0, ui.WIDTH, ui.HEIGHT, ui.BG) ui.display.avatar(48, 48 - 10, image, ui.WHITE, ui.BLACK) ui.display.text_center(ui.WIDTH // 2, 220, label, ui.BOLD, ui.FG, ui.BG) + + +def _warn(message: str): + ui.display.bar(0, 0, ui.WIDTH, 30, ui.YELLOW) + ui.display.text_center(ui.WIDTH // 2, 22, message, ui.BOLD, ui.BLACK, ui.YELLOW) + ui.display.bar(0, 30, ui.WIDTH, ui.HEIGHT - 30, ui.BG) + + +def _err(message: str): + ui.display.bar(0, 0, ui.WIDTH, 30, ui.RED) + ui.display.text_center(ui.WIDTH // 2, 22, message, ui.BOLD, ui.WHITE, ui.RED) + ui.display.bar(0, 30, ui.WIDTH, ui.HEIGHT - 30, ui.BG) diff --git a/core/src/apps/management/backup_device.py b/core/src/apps/management/backup_device.py index 15fec39423..2e6579e389 100644 --- a/core/src/apps/management/backup_device.py +++ b/core/src/apps/management/backup_device.py @@ -2,12 +2,8 @@ from trezor import wire from trezor.messages.Success import Success from apps.common import mnemonic, storage -from apps.management.reset_device import ( - check_mnemonic, - show_backup_warning, - show_mnemonic, - show_wrong_entry, -) +from apps.management.common import layout +from apps.management.reset_device import backup_slip39_wallet async def backup_device(ctx, msg): @@ -16,20 +12,18 @@ async def backup_device(ctx, msg): if not storage.needs_backup(): raise wire.ProcessError("Seed already backed up") - words = mnemonic.restore() - # warn user about mnemonic safety - await show_backup_warning(ctx) + await layout.bip39_show_backup_warning(ctx) storage.set_unfinished_backup(True) storage.set_backed_up() - while True: - # show mnemonic and require confirmation of a random word - await show_mnemonic(ctx, words) - if await check_mnemonic(ctx, words): - break - await show_wrong_entry(ctx) + mnemonic_secret, mnemonic_type = mnemonic.get() + if mnemonic_type == mnemonic.TYPE_BIP39: + await layout.bip39_show_and_confirm_mnemonic(ctx, mnemonic_secret.decode()) + + elif mnemonic_type == mnemonic.TYPE_SLIP39: + await backup_slip39_wallet(ctx, mnemonic_secret) storage.set_unfinished_backup(False) diff --git a/core/src/apps/management/common/layout.py b/core/src/apps/management/common/layout.py new file mode 100644 index 0000000000..4c348ad317 --- /dev/null +++ b/core/src/apps/management/common/layout.py @@ -0,0 +1,519 @@ +import ubinascii +from micropython import const + +from trezor import ui, utils +from trezor.crypto import random +from trezor.messages import ButtonRequestType +from trezor.ui.button import Button, ButtonDefault +from trezor.ui.checklist import Checklist +from trezor.ui.info import InfoConfirm +from trezor.ui.loader import LoadingAnimation +from trezor.ui.scroll import Paginated +from trezor.ui.shamir import NumInput +from trezor.ui.text import Text + +from apps.common.confirm import confirm, hold_to_confirm, require_confirm + +if __debug__: + from apps import debug + + +async def show_reset_device_warning(ctx, use_slip39: bool): + text = Text("Create new wallet", ui.ICON_RESET, new_lines=False) + text.bold("Do you want to create") + text.br() + if use_slip39: + text.bold("a new Shamir wallet?") + else: + text.bold("a new wallet?") + text.br() + text.br_half() + text.normal("By continuing you agree") + text.br() + text.normal("to") + text.bold("https://trezor.io/tos") + await require_confirm(ctx, text, ButtonRequestType.ResetDevice, major_confirm=True) + await LoadingAnimation() + + +async def show_internal_entropy(ctx, entropy: bytes): + entropy_str = ubinascii.hexlify(entropy).decode() + lines = utils.chunks(entropy_str, 16) + text = Text("Internal entropy", ui.ICON_RESET) + text.mono(*lines) + await require_confirm(ctx, text, ButtonRequestType.ResetDevice) + + +async def show_backup_success(ctx): + text = Text("Backup is done!", ui.ICON_CONFIRM, ui.GREEN) + text.normal( + "Never make a digital", + "copy of your recovery", + "seed and never upload", + "it online!", + ) + await require_confirm( + ctx, text, ButtonRequestType.ResetDevice, confirm="Finish setup", cancel=None + ) + + +async def confirm_backup(ctx): + text = Text("Backup wallet", ui.ICON_RESET, new_lines=False) + text.bold("New wallet created") + text.br() + text.bold("successfully!") + text.br() + text.br_half() + text.normal("You should back your") + text.br() + text.normal("new wallet right now.") + return await confirm( + ctx, + text, + ButtonRequestType.ResetDevice, + cancel="Skip", + confirm="Backup", + major_confirm=True, + ) + + +async def confirm_backup_again(ctx): + text = Text("Backup wallet", ui.ICON_RESET, new_lines=False) + text.bold("Are you sure you want") + text.br() + text.bold("to skip the backup?") + text.br() + text.br_half() + text.normal("You can backup Trezor") + text.br() + text.normal("anytime later.") + return await confirm( + ctx, + text, + ButtonRequestType.ResetDevice, + cancel="Skip", + confirm="Backup", + major_confirm=True, + ) + + +async def _confirm_share_words(ctx, share_index, share_words): + numbered = list(enumerate(share_words)) + + # check a word from the first half + first_half = numbered[: len(numbered) // 2] + if not await _confirm_word(ctx, share_index, first_half): + return False + + # check a word from the second half + second_half = numbered[len(numbered) // 2 :] + if not await _confirm_word(ctx, share_index, second_half): + return False + + return True + + +async def _confirm_word(ctx, share_index, numbered_share_words): + # TODO: duplicated words in the choice list + + # shuffle the numbered seed half, slice off the choices we need + random.shuffle(numbered_share_words) + numbered_choices = numbered_share_words[: MnemonicWordSelect.NUM_OF_CHOICES] + + # we always confirm the first (random) word index + checked_index, checked_word = numbered_choices[0] + if __debug__: + debug.reset_word_index = checked_index + + # shuffle again so the confirmed word is not always the first choice + random.shuffle(numbered_choices) + + # let the user pick a word + choices = [word for _, word in numbered_choices] + select = MnemonicWordSelect(choices, share_index, checked_index) + if __debug__: + selected_word = await ctx.wait(select, debug.input_signal) + else: + selected_word = await ctx.wait(select) + + # confirm it is the correct one + return selected_word == checked_word + + +async def _show_confirmation_success(ctx, share_index): + if share_index is None: + text = Text("Recovery seed", ui.ICON_RESET) + text.bold("Recovery seed") + text.bold("checked successfully.") + else: + text = Text("Recovery share #%s" % (share_index + 1), ui.ICON_RESET) + text.bold("Seed share #%s" % (share_index + 1)) + text.bold("checked successfully.") + text.normal("Let's continue with") + text.normal("share #%s." % (share_index + 2)) + return await confirm( + ctx, text, ButtonRequestType.ResetDevice, cancel=None, confirm="Continue" + ) + + +async def _show_confirmation_failure(ctx, share_index): + if share_index is None: + text = Text("Recovery seed", ui.ICON_WRONG, ui.RED) + else: + text = Text("Recovery share #%s" % (share_index + 1), ui.ICON_WRONG, ui.RED) + text.bold("You have entered") + text.bold("wrong seed word.") + text.bold("Please check again.") + await require_confirm( + ctx, text, ButtonRequestType.ResetDevice, confirm="Check again", cancel=None + ) + + +# BIP39 +# === + + +async def bip39_show_and_confirm_mnemonic(ctx, mnemonic: str): + words = mnemonic.split() + + # require confirmation of the mnemonic safety + await bip39_show_backup_warning(ctx) + + while True: + # display paginated mnemonic on the screen + await _bip39_show_mnemonic(ctx, words) + + # make the user confirm 2 words from the mnemonic + if await _confirm_share_words(ctx, None, words): + await _show_confirmation_success(ctx, None) + break # this share is confirmed, go to next one + else: + await _show_confirmation_failure(ctx, None) + + +async def bip39_show_backup_warning(ctx): + text = Text("Backup your seed", ui.ICON_NOCOPY) + text.normal( + "Never make a digital", + "copy of your recovery", + "seed and never upload", + "it online!", + ) + await require_confirm( + ctx, text, ButtonRequestType.ResetDevice, confirm="I understand", cancel=None + ) + + +async def _bip39_show_mnemonic(ctx, words: list): + # split mnemonic words into pages + PER_PAGE = const(4) + words = list(enumerate(words)) + words = list(utils.chunks(words, PER_PAGE)) + + # display the pages, with a confirmation dialog on the last one + pages = [_get_mnemonic_page(page) for page in words] + paginated = Paginated(pages) + + if __debug__: + + def export_displayed_words(): + # export currently displayed mnemonic words into debuglink + debug.reset_current_words = [w for _, w in words[paginated.page]] + + paginated.on_change = export_displayed_words + export_displayed_words() + + await hold_to_confirm(ctx, paginated, ButtonRequestType.ResetDevice) + + +def _get_mnemonic_page(words: list): + text = Text("Recovery seed", ui.ICON_RESET) + for index, word in words: + text.mono("%2d. %s" % (index + 1, word)) + return text + + +# SLIP39 +# === + +# TODO: yellow cancel style? +# TODO: loading animation style? +# TODO: smaller font or tighter rows to fit more text in +# TODO: icons in checklist + + +async def slip39_show_checklist_set_shares(ctx): + checklist = Checklist("Backup checklist", ui.ICON_RESET) + checklist.add("Set number of shares") + checklist.add("Set the threshold") + checklist.add(("Write down and check", "all seed shares")) + checklist.select(0) + checklist.process() + return await confirm( + ctx, checklist, ButtonRequestType.ResetDevice, cancel=None, confirm="Set shares" + ) + + +async def slip39_show_checklist_set_threshold(ctx, num_of_shares): + checklist = Checklist("Backup checklist", ui.ICON_RESET) + checklist.add("Set number of shares") + checklist.add("Set the threshold") + checklist.add(("Write down and check", "all seed shares")) + checklist.select(1) + checklist.process() + return await confirm( + ctx, + checklist, + ButtonRequestType.ResetDevice, + cancel=None, + confirm="Set threshold", + ) + + +async def slip39_show_checklist_show_shares(ctx, num_of_shares, threshold): + checklist = Checklist("Backup checklist", ui.ICON_RESET) + checklist.add("Set number of shares") + checklist.add("Set the threshold") + checklist.add(("Write down and check", "all seed shares")) + checklist.select(2) + checklist.process() + return await confirm( + ctx, + checklist, + ButtonRequestType.ResetDevice, + cancel=None, + confirm="Show seed shares", + ) + + +async def slip39_prompt_number_of_shares(ctx): + count = 5 + min_count = 2 + max_count = 16 + + while True: + shares = ShamirNumInput(ShamirNumInput.SET_SHARES, count, min_count, max_count) + info = InfoConfirm( + "Shares are parts of " + "the recovery seed, " + "each containing 20 " + "words. You can later set " + "how many shares you " + "need to recover your " + "wallet." + ) + confirmed = await confirm( + ctx, + shares, + ButtonRequestType.ResetDevice, + cancel="Info", + confirm="Set", + major_confirm=True, + cancel_style=ButtonDefault, + ) + count = shares.input.count + if confirmed: + break + else: + await info + + return count + + +async def slip39_prompt_threshold(ctx, num_of_shares): + count = num_of_shares // 2 + min_count = 2 + max_count = num_of_shares + + while True: + shares = ShamirNumInput( + ShamirNumInput.SET_THRESHOLD, count, min_count, max_count + ) + info = InfoConfirm( + "Threshold sets number " + "shares that you need " + "to recover your wallet. " + "i.e. Set it to %s and " + "you'll need any %s shares " + "of the total number." % (count, count) + ) + confirmed = await confirm( + ctx, + shares, + ButtonRequestType.ResetDevice, + cancel="Info", + confirm="Set", + major_confirm=True, + cancel_style=ButtonDefault, + ) + count = shares.input.count + if confirmed: + break + else: + await info + + return count + + +async def slip39_show_and_confirm_shares(ctx, shares): + for index, share in enumerate(shares): + share_words = share.split(" ") + while True: + # display paginated share on the screen + await _slip39_show_share_words(ctx, index, share_words) + + # make the user confirm 2 words from the share + if await _confirm_share_words(ctx, index, share_words): + await _show_confirmation_success(ctx, index) + break # this share is confirmed, go to next one + else: + await _show_confirmation_failure(ctx, index) + + +async def _slip39_show_share_words(ctx, share_index, share_words): + first, chunks, last = _slip39_split_share_into_pages(share_words) + + if share_index is None: + header_title = "Recovery share #%s" % (share_index + 1) + else: + header_title = "Recovery seed" + header_icon = ui.ICON_RESET + pages = [] # ui page components + shares_words_check = [] # check we display correct data + + # first page + text = Text(header_title, header_icon) + text.normal("Write down %s words" % len(share_words)) + text.normal("onto paper booklet:") + text.br_half() + for index, word in first: + text.mono("%s. %s" % (index + 1, word)) + shares_words_check.append(word) + pages.append(text) + + # middle pages + for chunk in chunks: + text = Text(header_title, header_icon) + text.br_half() + for index, word in chunk: + text.mono("%s. %s" % (index + 1, word)) + shares_words_check.append(word) + pages.append(text) + + # last page + text = Text(header_title, header_icon) + for index, word in last: + text.mono("%s. %s" % (index + 1, word)) + shares_words_check.append(word) + text.br_half() + text.normal("I confirm that I wrote") + text.normal("down all %s words." % len(share_words)) + pages.append(text) + + # pagination + paginated = Paginated(pages) + + if __debug__: + + word_pages = [first] + chunks + [last] + + def export_displayed_words(): + # export currently displayed mnemonic words into debuglink + debug.reset_current_words = word_pages[paginated.page] + + paginated.on_change = export_displayed_words + export_displayed_words() + + # make sure we display correct data + utils.ensure(share_words == shares_words_check) + + # confirm the share + await hold_to_confirm(ctx, paginated) # TODO: customize the loader here + + +def _slip39_split_share_into_pages(share_words): + share = list(enumerate(share_words)) # we need to keep track of the word indices + first = share[:2] # two words on the first page + middle = share[2:-2] + last = share[-2:] # two words on the last page + chunks = utils.chunks(middle, 4) # 4 words on the middle pages + return first, list(chunks), last + + +class ShamirNumInput(ui.Control): + SET_SHARES = object() + SET_THRESHOLD = object() + + def __init__(self, step, count, min_count, max_count): + self.step = step + self.input = NumInput(count, min_count=min_count, max_count=max_count) + self.input.on_change = self.on_change + self.repaint = True + + def dispatch(self, event, x, y): + self.input.dispatch(event, x, y) + if event is ui.RENDER: + self.on_render() + + def on_render(self): + if self.repaint: + count = self.input.count + + # render the headline + if self.step is ShamirNumInput.SET_SHARES: + header = "Set num. of shares" + elif self.step is ShamirNumInput.SET_THRESHOLD: + header = "Set the threshold" + ui.header(header, ui.ICON_RESET, ui.TITLE_GREY, ui.BG, ui.ORANGE_ICON) + + # render the counter + if self.step is ShamirNumInput.SET_SHARES: + ui.display.text( + 12, 130, "%s people or locations" % count, ui.BOLD, ui.FG, ui.BG + ) + ui.display.text( + 12, 156, "will each host one share.", ui.NORMAL, ui.FG, ui.BG + ) + elif self.step is ShamirNumInput.SET_THRESHOLD: + ui.display.text( + 12, 130, "For recovery you'll need", ui.NORMAL, ui.FG, ui.BG + ) + ui.display.text( + 12, 156, "any %s of shares." % count, ui.BOLD, ui.FG, ui.BG + ) + + self.repaint = False + + def on_change(self, count): + self.repaint = True + + +class MnemonicWordSelect(ui.Layout): + NUM_OF_CHOICES = 3 + + def __init__(self, words, share_index, word_index): + self.words = words + self.share_index = share_index + self.word_index = word_index + self.buttons = [] + for i, word in enumerate(words): + area = ui.grid(i + 2, n_x=1) + btn = Button(area, word) + btn.on_click = self.select(word) + self.buttons.append(btn) + if share_index is None: + self.text = Text("Recovery seed") + else: + self.text = Text("Recovery share #%s" % (share_index + 1)) + self.text.normal("Choose the %s word:" % utils.format_ordinal(word_index + 1)) + + def dispatch(self, event, x, y): + for btn in self.buttons: + btn.dispatch(event, x, y) + self.text.dispatch(event, x, y) + + def select(self, word): + def fn(): + raise ui.Result(word) + + return fn diff --git a/core/src/apps/management/load_device.py b/core/src/apps/management/load_device.py index a0b1b971a5..375674b57e 100644 --- a/core/src/apps/management/load_device.py +++ b/core/src/apps/management/load_device.py @@ -1,15 +1,15 @@ from trezor import config, wire -from trezor.crypto import bip39 from trezor.messages.Success import Success from trezor.pin import pin_to_int from trezor.ui.text import Text -from apps.common import mnemonic, storage +from apps.common import storage from apps.common.confirm import require_confirm +from apps.common.mnemonic import bip39 async def load_device(ctx, msg): - + # TODO implement SLIP-39 if storage.is_initialized(): raise wire.UnexpectedMessage("Already initialized") @@ -24,10 +24,10 @@ async def load_device(ctx, msg): text.normal("Continue only if you", "know what you are doing!") await require_confirm(ctx, text) - secret = mnemonic.process([msg.mnemonic], mnemonic.TYPE_BIP39) + secret = bip39.process_all([msg.mnemonic]) storage.store_mnemonic( secret=secret, - mnemonic_type=mnemonic.TYPE_BIP39, + mnemonic_type=bip39.get_type(), needs_backup=True, no_backup=False, ) diff --git a/core/src/apps/management/recovery_device.py b/core/src/apps/management/recovery_device.py index 6b9038d452..ecb1dfff0c 100644 --- a/core/src/apps/management/recovery_device.py +++ b/core/src/apps/management/recovery_device.py @@ -1,31 +1,28 @@ from trezor import config, ui, wire -from trezor.crypto import bip39 -from trezor.crypto.hashlib import sha256 +from trezor.messages import ButtonRequestType from trezor.messages.ButtonRequest import ButtonRequest -from trezor.messages.ButtonRequestType import ( - MnemonicInput, - MnemonicWordCount, - ProtectCall, -) from trezor.messages.MessageType import ButtonAck from trezor.messages.Success import Success from trezor.pin import pin_to_int -from trezor.ui.mnemonic import MnemonicKeyboard +from trezor.ui.info import InfoConfirm +from trezor.ui.mnemonic_bip39 import Bip39Keyboard +from trezor.ui.mnemonic_slip39 import Slip39Keyboard from trezor.ui.text import Text from trezor.ui.word_select import WordSelector -from trezor.utils import consteq, format_ordinal +from trezor.utils import format_ordinal from apps.common import mnemonic, storage from apps.common.confirm import require_confirm +from apps.homescreen.homescreen import display_homescreen from apps.management.change_pin import request_pin_ack, request_pin_confirm if __debug__: - from apps.debug import input_signal + from apps.debug import confirm_signal, input_signal async def recovery_device(ctx, msg): """ - Recover BIP39 seed into empty device. + Recover BIP39/SLIP39 seed into empty device. 1. Ask for the number of words in recovered seed. 2. Let user type in the mnemonic words one by one. @@ -36,34 +33,53 @@ async def recovery_device(ctx, msg): if not msg.dry_run and storage.is_initialized(): raise wire.UnexpectedMessage("Already initialized") - if not msg.dry_run: - title = "Device recovery" - text = Text(title, ui.ICON_RECOVERY) - text.normal("Do you really want to", "recover the device?", "") - else: - title = "Simulated recovery" - text = Text(title, ui.ICON_RECOVERY) - text.normal("Do you really want to", "check the recovery", "seed?") - - await require_confirm(ctx, text, code=ProtectCall) - - if msg.dry_run: - if config.has_pin(): - curpin = await request_pin_ack(ctx, "Enter PIN", config.get_pin_rem()) + if not storage.is_slip39_in_progress(): + if not msg.dry_run: + title = "Device recovery" + text = Text(title, ui.ICON_RECOVERY) + text.normal("Do you really want to", "recover the device?", "") else: - curpin = "" - if not config.check_pin(pin_to_int(curpin)): - raise wire.PinInvalid("PIN invalid") + title = "Simulated recovery" + text = Text(title, ui.ICON_RECOVERY) + text.normal("Do you really want to", "check the recovery", "seed?") + await require_confirm(ctx, text, code=ButtonRequestType.ProtectCall) - # ask for the number of words - wordcount = await request_wordcount(ctx, title) + if msg.dry_run: + if config.has_pin(): + curpin = await request_pin_ack(ctx, "Enter PIN", config.get_pin_rem()) + else: + curpin = "" + if not config.check_pin(pin_to_int(curpin)): + raise wire.PinInvalid("PIN invalid") - # ask for mnemonic words one by one - words = await request_mnemonic(ctx, wordcount) + # ask for the number of words + wordcount = await request_wordcount(ctx, title) + mnemonic_module = mnemonic.module_from_words_count(wordcount) + else: + wordcount = storage.get_slip39_words_count() + mnemonic_module = mnemonic.slip39 + + if mnemonic_module == mnemonic.slip39: + # show a note about the keyboard + await show_keyboard_info(ctx) + + secret = None + while secret is None: + # ask for mnemonic words one by one + words = await request_mnemonic( + ctx, wordcount, mnemonic_module == mnemonic.slip39 + ) + secret = mnemonic_module.process_single(words) + # show a number of remaining mnemonics for SLIP39 + if secret is None and mnemonic_module == mnemonic.slip39: + await show_remaining_slip39_mnemonics( + ctx, title, storage.get_slip39_remaining() + ) # check mnemonic validity - if msg.enforce_wordlist or msg.dry_run: - if not bip39.check(words): + # it is checked automatically in SLIP-39 + if mnemonic_module == mnemonic.bip39 and (msg.enforce_wordlist or msg.dry_run): + if not mnemonic_module.check(secret): raise wire.ProcessError("Mnemonic is not valid") # ask for pin repeatedly @@ -72,39 +88,24 @@ async def recovery_device(ctx, msg): else: newpin = "" - secret = mnemonic.process([words], mnemonic.TYPE_BIP39) - # dry run if msg.dry_run: - digest_input = sha256(secret).digest() - stored, _ = mnemonic.get() - digest_stored = sha256(stored).digest() - if consteq(digest_stored, digest_input): - return Success( - message="The seed is valid and matches the one in the device" - ) - else: - raise wire.ProcessError( - "The seed is valid but does not match the one in the device" - ) + mnemonic.dry_run(secret) # save into storage - if newpin: + if msg.pin_protection: config.change_pin(pin_to_int(""), pin_to_int(newpin)) storage.set_u2f_counter(msg.u2f_counter) storage.load_settings(label=msg.label, use_passphrase=msg.passphrase_protection) - storage.store_mnemonic( - secret=secret, - mnemonic_type=mnemonic.TYPE_BIP39, - needs_backup=False, - no_backup=False, - ) + mnemonic_module.store(secret=secret, needs_backup=False, no_backup=False) + + display_homescreen() return Success(message="Device recovered") async def request_wordcount(ctx, title: str) -> int: - await ctx.call(ButtonRequest(code=MnemonicWordCount), ButtonAck) + await ctx.call(ButtonRequest(code=ButtonRequestType.MnemonicWordCount), ButtonAck) text = Text(title, ui.ICON_RECOVERY) text.normal("Number of words?") @@ -118,12 +119,15 @@ async def request_wordcount(ctx, title: str) -> int: return count -async def request_mnemonic(ctx, count: int) -> str: - await ctx.call(ButtonRequest(code=MnemonicInput), ButtonAck) +async def request_mnemonic(ctx, count: int, slip39: bool) -> str: + await ctx.call(ButtonRequest(code=ButtonRequestType.MnemonicInput), ButtonAck) words = [] for i in range(count): - keyboard = MnemonicKeyboard("Type the %s word:" % format_ordinal(i + 1)) + if slip39: + keyboard = Slip39Keyboard("Type the %s word:" % format_ordinal(i + 1)) + else: + keyboard = Bip39Keyboard("Type the %s word:" % format_ordinal(i + 1)) if __debug__: word = await ctx.wait(keyboard, input_signal) else: @@ -131,3 +135,33 @@ async def request_mnemonic(ctx, count: int) -> str: words.append(word) return " ".join(words) + + +async def show_keyboard_info(ctx): + await ctx.call(ButtonRequest(code=ButtonRequestType.Other), ButtonAck) + + info = InfoConfirm( + "One more thing. " + "You can type the letters " + "the old-fashioned way " + "one by one or use our " + "T9 keyboard and press " + "buttons only once." + ) + if __debug__: + await ctx.wait(info, confirm_signal) + else: + await ctx.wait(info) + + +async def show_remaining_slip39_mnemonics(ctx, title, remaining: int): + text = Text(title, ui.ICON_RECOVERY) + text.bold("Good job!") + if remaining > 1: + text.normal("%s more shares" % remaining) + else: + text.normal("%s more share" % remaining) + text.normal("needed to enter.") + await require_confirm( + ctx, text, ButtonRequestType.ProtectCall, cancel=None, confirm="Continue" + ) diff --git a/core/src/apps/management/reset_device.py b/core/src/apps/management/reset_device.py index 25fab76b3d..a72b338d42 100644 --- a/core/src/apps/management/reset_device.py +++ b/core/src/apps/management/reset_device.py @@ -1,20 +1,13 @@ -from micropython import const -from ubinascii import hexlify - -from trezor import config, ui, wire +from trezor import config, wire from trezor.crypto import bip39, hashlib, random -from trezor.messages import ButtonRequestType, MessageType +from trezor.messages import MessageType from trezor.messages.EntropyRequest import EntropyRequest from trezor.messages.Success import Success from trezor.pin import pin_to_int -from trezor.ui.mnemonic import MnemonicKeyboard -from trezor.ui.scroll import Paginated -from trezor.ui.text import Text -from trezor.utils import chunks, format_ordinal from apps.common import mnemonic, storage -from apps.common.confirm import hold_to_confirm, require_confirm from apps.management.change_pin import request_pin_confirm +from apps.management.common import layout if __debug__: from apps import debug @@ -22,15 +15,10 @@ if __debug__: async def reset_device(ctx, msg): # validate parameters and device state - if msg.strength not in (128, 192, 256): - raise wire.ProcessError("Invalid strength (has to be 128, 192 or 256 bits)") - if msg.display_random and (msg.skip_backup or msg.no_backup): - raise wire.ProcessError("Can't show internal entropy when backup is skipped") - if storage.is_initialized(): - raise wire.UnexpectedMessage("Already initialized") + _validate_reset_device(msg) - # make sure use knows he's setting up a new wallet - await show_reset_warning(ctx) + # make sure user knows he's setting up a new wallet + await layout.show_reset_device_warning(ctx, msg.slip39) # request new PIN if msg.pin_protection: @@ -39,165 +27,100 @@ async def reset_device(ctx, msg): newpin = "" # generate and display internal entropy - internal_ent = random.bytes(32) + int_entropy = random.bytes(32) if __debug__: - debug.reset_internal_entropy = internal_ent + debug.reset_internal_entropy = int_entropy if msg.display_random: - await show_entropy(ctx, internal_ent) + await layout.show_internal_entropy(ctx, int_entropy) - # request external entropy and compute mnemonic - ent_ack = await ctx.call(EntropyRequest(), MessageType.EntropyAck) - words = generate_mnemonic(msg.strength, internal_ent, ent_ack.entropy) + # request external entropy and compute the master secret + entropy_ack = await ctx.call(EntropyRequest(), MessageType.EntropyAck) + ext_entropy = entropy_ack.entropy + secret = _compute_secret_from_entropy(int_entropy, ext_entropy, msg.strength) - if not msg.skip_backup and not msg.no_backup: - # require confirmation of the mnemonic safety - await show_backup_warning(ctx) + # should we back up the wallet now? + if not msg.no_backup and not msg.skip_backup: + if not await layout.confirm_backup(ctx): + if not await layout.confirm_backup_again(ctx): + msg.skip_backup = True - # show mnemonic and require confirmation of a random word - while True: - await show_mnemonic(ctx, words) - if await check_mnemonic(ctx, words): - break - await show_wrong_entry(ctx) + # generate and display backup information for the master secret + if not msg.no_backup and not msg.skip_backup: + if msg.slip39: + await backup_slip39_wallet(ctx, secret) + else: + await backup_bip39_wallet(ctx, secret) # write PIN into storage - if newpin: - if not config.change_pin(pin_to_int(""), pin_to_int(newpin)): - raise wire.ProcessError("Could not change PIN") + if not config.change_pin(pin_to_int(""), pin_to_int(newpin)): + raise wire.ProcessError("Could not change PIN") - secret = mnemonic.process([words], mnemonic.TYPE_BIP39) - # write settings and mnemonic into storage + # write settings and master secret into storage storage.load_settings(label=msg.label, use_passphrase=msg.passphrase_protection) - storage.store_mnemonic( - secret=secret, - mnemonic_type=mnemonic.TYPE_BIP39, - needs_backup=msg.skip_backup, - no_backup=msg.no_backup, - ) + if msg.slip39: + mnemonic.slip39.store( + secret=secret, needs_backup=msg.skip_backup, no_backup=msg.no_backup + ) + else: + # in BIP-39 we store mnemonic string instead of the secret + mnemonic.bip39.store( + secret=bip39.from_data(secret).encode(), + needs_backup=msg.skip_backup, + no_backup=msg.no_backup, + ) - # show success message - if not msg.skip_backup and not msg.no_backup: - await show_success(ctx) + # if we backed up the wallet, show success message + if not msg.no_backup and not msg.skip_backup: + await layout.show_backup_success(ctx) return Success(message="Initialized") -def generate_mnemonic(strength: int, int_entropy: bytes, ext_entropy: bytes) -> bytes: +async def backup_slip39_wallet(ctx, secret: bytes): + # get number of shares + await layout.slip39_show_checklist_set_shares(ctx) + shares_count = await layout.slip39_prompt_number_of_shares(ctx) + + # get threshold + await layout.slip39_show_checklist_set_threshold(ctx, shares_count) + threshold = await layout.slip39_prompt_threshold(ctx, shares_count) + + # generate the mnemonics + mnemonics = mnemonic.slip39.generate_from_secret(secret, shares_count, threshold) + + # show and confirm individual shares + await layout.slip39_show_checklist_show_shares(ctx, shares_count, threshold) + await layout.slip39_show_and_confirm_shares(ctx, mnemonics) + + +async def backup_bip39_wallet(ctx, secret: bytes): + mnemonic = bip39.from_data(secret) + await layout.bip39_show_and_confirm_mnemonic(ctx, mnemonic) + + +def _validate_reset_device(msg): + if msg.strength not in (128, 256): + if msg.slip39: + raise wire.ProcessError("Invalid strength (has to be 128 or 256 bits)") + elif msg.strength != 192: + raise wire.ProcessError("Invalid strength (has to be 128, 192 or 256 bits)") + if msg.display_random and (msg.skip_backup or msg.no_backup): + raise wire.ProcessError("Can't show internal entropy when backup is skipped") + if storage.is_initialized(): + raise wire.UnexpectedMessage("Already initialized") + if (msg.skip_backup or msg.no_backup) and msg.slip39: + raise wire.ProcessError("Both no/skip backup flag and Shamir SLIP-39 required.") + + +def _compute_secret_from_entropy( + int_entropy: bytes, ext_entropy: bytes, strength_in_bytes: int +) -> bytes: + # combine internal and external entropy ehash = hashlib.sha256() ehash.update(int_entropy) ehash.update(ext_entropy) entropy = ehash.digest() - return bip39.from_data(entropy[: strength // 8]) - - -async def show_reset_warning(ctx): - text = Text("Create a new wallet", ui.ICON_RESET, new_lines=False) - text.normal("Do you really want to") - text.br() - text.normal("create a new wallet?") - text.br() - text.br_half() - text.normal("By continuing you agree") - text.br() - text.normal("to") - text.bold("https://trezor.io/tos") - await require_confirm(ctx, text, code=ButtonRequestType.ResetDevice) - - -async def show_backup_warning(ctx): - text = Text("Backup your seed", ui.ICON_NOCOPY) - text.normal( - "Never make a digital", - "copy of your recovery", - "seed and never upload", - "it online!", - ) - await require_confirm( - ctx, text, ButtonRequestType.ResetDevice, confirm="I understand", cancel=None - ) - - -async def show_wrong_entry(ctx): - text = Text("Wrong entry!", ui.ICON_WRONG, ui.RED) - text.normal("You have entered", "wrong seed word.", "Please check again.") - await require_confirm( - ctx, text, ButtonRequestType.ResetDevice, confirm="Check again", cancel=None - ) - - -async def show_success(ctx): - text = Text("Backup is done!", ui.ICON_CONFIRM, ui.GREEN) - text.normal( - "Never make a digital", - "copy of your recovery", - "seed and never upload", - "it online!", - ) - await require_confirm( - ctx, text, ButtonRequestType.ResetDevice, confirm="Finish setup", cancel=None - ) - - -async def show_entropy(ctx, entropy: bytes): - entropy_str = hexlify(entropy).decode() - lines = chunks(entropy_str, 16) - text = Text("Internal entropy", ui.ICON_RESET) - text.mono(*lines) - await require_confirm(ctx, text, ButtonRequestType.ResetDevice) - - -async def show_mnemonic(ctx, mnemonic: str): - # split mnemonic words into pages - PER_PAGE = const(4) - words = mnemonic.split() - words = list(enumerate(words)) - words = list(chunks(words, PER_PAGE)) - - # display the pages, with a confirmation dialog on the last one - pages = [get_mnemonic_page(page) for page in words] - paginated = Paginated(pages) - - if __debug__: - - def export_displayed_words(): - # export currently displayed mnemonic words into debuglink - debug.reset_current_words = [w for _, w in words[paginated.page]] - - paginated.on_change = export_displayed_words - export_displayed_words() - - await hold_to_confirm(ctx, paginated, ButtonRequestType.ResetDevice) - - -def get_mnemonic_page(words: list): - text = Text("Recovery seed", ui.ICON_RESET) - for index, word in words: - text.mono("%2d. %s" % (index + 1, word)) - return text - - -async def check_mnemonic(ctx, mnemonic: str) -> bool: - words = mnemonic.split() - - # check a word from the first half - index = random.uniform(len(words) // 2) - if not await check_word(ctx, words, index): - return False - - # check a word from the second half - index = random.uniform(len(words) // 2) + len(words) // 2 - if not await check_word(ctx, words, index): - return False - - return True - - -async def check_word(ctx, words: list, index: int): - if __debug__: - debug.reset_word_index = index - keyboard = MnemonicKeyboard("Type the %s word:" % format_ordinal(index + 1)) - if __debug__: - result = await ctx.wait(keyboard, debug.input_signal) - else: - result = await ctx.wait(keyboard) - return result == words[index] + # take a required number of bytes + strength = strength_in_bytes // 8 + secret = entropy[:strength] + return secret diff --git a/core/src/trezor/crypto/slip39.py b/core/src/trezor/crypto/slip39.py index eb6c380a5a..ad05e892fa 100644 --- a/core/src/trezor/crypto/slip39.py +++ b/core/src/trezor/crypto/slip39.py @@ -21,8 +21,23 @@ from micropython import const from trezor.crypto import hashlib, hmac, pbkdf2, random -from trezor.crypto.slip39_wordlist import wordlist -from trezorcrypto import shamir +from trezorcrypto import shamir, slip39 + +_KEYBOARD_FULL_MASK = const(0x1FF) +"""All buttons are allowed. 9-bit bitmap all set to 1.""" + + +def compute_mask(prefix: str) -> int: + if not prefix: + return _KEYBOARD_FULL_MASK + return slip39.compute_mask(int(prefix)) + + +def button_sequence_to_word(prefix: str) -> str: + if not prefix: + return _KEYBOARD_FULL_MASK + return slip39.button_sequence_to_word(int(prefix)) + _RADIX_BITS = const(10) """The length of the radix in bits.""" @@ -36,6 +51,11 @@ def bits_to_words(n): return (n + _RADIX_BITS - 1) // _RADIX_BITS +MAX_SHARE_COUNT = const(16) +"""The maximum number of shares that can be created.""" + +DEFAULT_ITERATION_EXPONENT = const(0) + _RADIX = 2 ** _RADIX_BITS """The number of words in the wordlist.""" @@ -48,9 +68,6 @@ _ITERATION_EXP_LENGTH_BITS = const(5) _ID_EXP_LENGTH_WORDS = bits_to_words(_ID_LENGTH_BITS + _ITERATION_EXP_LENGTH_BITS) """The length of the random identifier and iteration exponent in words.""" -_MAX_SHARE_COUNT = const(16) -"""The maximum number of shares that can be created.""" - _CHECKSUM_LENGTH_WORDS = const(3) """The length of the RS1024 checksum in words.""" @@ -86,21 +103,6 @@ class MnemonicError(Exception): pass -def word_index(word): - word = word + " " * (8 - len(word)) - lo = 0 - hi = _RADIX - while hi - lo > 1: - mid = (hi + lo) // 2 - if wordlist[mid * 8 : mid * 8 + 8] > word: - hi = mid - else: - lo = mid - if wordlist[lo * 8 : lo * 8 + 8] != word: - raise MnemonicError('Invalid mnemonic word "{}".'.format(word)) - return lo - - def _rs1024_polymod(values): GEN = ( 0xE0E040, @@ -181,11 +183,11 @@ def _int_to_indices(value, length, bits): def mnemonic_from_indices(indices): - return " ".join(wordlist[i * 8 : i * 8 + 8].strip() for i in indices) + return " ".join(slip39.get_word(i) for i in indices) def mnemonic_to_indices(mnemonic): - return (word_index(word.lower()) for word in mnemonic.split()) + return (slip39.word_index(word.lower()) for word in mnemonic.split()) def _round_function(i, passphrase, e, salt, r): @@ -247,10 +249,10 @@ def _split_secret(threshold, share_count, shared_secret): ) ) - if share_count > _MAX_SHARE_COUNT: + if share_count > MAX_SHARE_COUNT: raise ValueError( "The requested number of shares ({}) must not exceed {}.".format( - share_count, _MAX_SHARE_COUNT + share_count, MAX_SHARE_COUNT ) ) @@ -462,16 +464,33 @@ def _decode_mnemonics(mnemonics): ) -def _generate_random_identifier(): +def _generate_random_identifier() -> int: """Returns a randomly generated integer in the range 0, ... , 2**_ID_LENGTH_BITS - 1.""" identifier = int.from_bytes(random.bytes(bits_to_bytes(_ID_LENGTH_BITS)), "big") return identifier & ((1 << _ID_LENGTH_BITS) - 1) -def generate_mnemonics( - group_threshold, groups, master_secret, passphrase=b"", iteration_exponent=0 -): +def generate_single_group_mnemonics_from_data( + master_secret, + threshold, + count, + passphrase=b"", + iteration_exponent=DEFAULT_ITERATION_EXPONENT, +) -> (int, list): + identifier, mnemonics = generate_mnemonics_from_data( + master_secret, 1, [(threshold, count)], passphrase, iteration_exponent + ) + return identifier, mnemonics[0] + + +def generate_mnemonics_from_data( + master_secret, + group_threshold, + groups, + passphrase=b"", + iteration_exponent=DEFAULT_ITERATION_EXPONENT, +) -> (int, list): """ Splits a master secret into mnemonic shares using Shamir's secret sharing scheme. :param int group_threshold: The number of groups required to reconstruct the master secret. @@ -486,6 +505,8 @@ def generate_mnemonics( :param int iteration_exponent: The iteration exponent. :return: List of mnemonics. :rtype: List of byte arrays. + :return: Identifier. + :rtype: int. """ identifier = _generate_random_identifier() @@ -528,68 +549,28 @@ def generate_mnemonics( group_shares = _split_secret(group_threshold, len(groups), encrypted_master_secret) - return [ - [ - encode_mnemonic( - identifier, - iteration_exponent, - group_index, - group_threshold, - len(groups), - member_index, - member_threshold, - value, + mnemonics = [] + for (member_threshold, member_count), (group_index, group_secret) in zip( + groups, group_shares + ): + group_mnemonics = [] + for member_index, value in _split_secret( + member_threshold, member_count, group_secret + ): + group_mnemonics.append( + encode_mnemonic( + identifier, + iteration_exponent, + group_index, + group_threshold, + len(groups), + member_index, + member_threshold, + value, + ) ) - for member_index, value in _split_secret( - member_threshold, member_count, group_secret - ) - ] - for (member_threshold, member_count), (group_index, group_secret) in zip( - groups, group_shares - ) - ] - - -def generate_mnemonics_random( - group_threshold, groups, strength_bits=128, passphrase=b"", iteration_exponent=0 -): - """ - Generates a random master secret and splits it into mnemonic shares using Shamir's secret - sharing scheme. - :param int group_threshold: The number of groups required to reconstruct the master secret. - :param groups: A list of (member_threshold, member_count) pairs for each group, where member_count - is the number of shares to generate for the group and member_threshold is the number of members required to - reconstruct the group secret. - :type groups: List of pairs of integers. - :param int strength_bits: The entropy of the randomly generated master secret in bits. - :param passphrase: The passphrase used to encrypt the master secret. - :type passphrase: Array of bytes. - :param int iteration_exponent: The iteration exponent. - :return: List of mnemonics. - :rtype: List of byte arrays. - """ - - if strength_bits < _MIN_STRENGTH_BITS: - raise ValueError( - "The requested strength of the master secret ({} bits) must be at least {} bits.".format( - strength_bits, _MIN_STRENGTH_BITS - ) - ) - - if strength_bits % 16 != 0: - raise ValueError( - "The requested strength of the master secret ({} bits) must be a multiple of 16 bits.".format( - strength_bits - ) - ) - - return generate_mnemonics( - group_threshold, - groups, - random.bytes(strength_bits // 8), - passphrase, - iteration_exponent, - ) + mnemonics.append(group_mnemonics) + return identifier, mnemonics def combine_mnemonics(mnemonics): @@ -597,7 +578,7 @@ def combine_mnemonics(mnemonics): Combines mnemonic shares to obtain the master secret which was previously split using Shamir's secret sharing scheme. :param mnemonics: List of mnemonics. - :type mnemonics: List of byte arrays. + :type mnemonics: List of strings. :return: Identifier, iteration exponent, the encrypted master secret. :rtype: Integer, integer, array of bytes. """ diff --git a/core/src/trezor/crypto/slip39_wordlist.py b/core/src/trezor/crypto/slip39_wordlist.py deleted file mode 100644 index 95815eaefc..0000000000 --- a/core/src/trezor/crypto/slip39_wordlist.py +++ /dev/null @@ -1 +0,0 @@ -wordlist = "academicacid acne acquire acrobat activityactress adapt adequateadjust admit adorn adult advance advocateafraid again agency agree aide aircraftairline airport ajar alarm album alcohol alien alive alpha already alto aluminumalways amazing ambitionamount amuse analysisanatomy ancestorancient angel angry animal answer antenna anxiety apart aquatic arcade arena argue armed artist artwork aspect auction august aunt average aviationavoid award away axis axle beam beard beaver become bedroom behaviorbeing believe belong benefit best beyond bike biology birthdaybishop black blanket blessingblimp blind blue body bolt boring born both boundarybraceletbranch brave breathe briefingbroken brother browser bucket budget buildingbulb bulge bumpy bundle burden burning busy buyer cage calcium camera campus canyon capacitycapital capture carbon cards careful cargo carpet carve categorycause ceiling center ceramic championchange charity check chemicalchest chew chubby cinema civil class clay cleanup client climate clinic clock clogs closet clothes club cluster coal coastal coding column company corner costume counter course cover cowboy cradle craft crazy credit cricket criminalcrisis criticalcrowd crucial crunch crush crystal cubic culturalcurious curly custody cylinderdaisy damage dance darknessdatabasedaughterdeadlinedeal debris debut decent decisiondeclare decoratedecreasedeliver demand density deny depart depend depict deploy describedesert desire desktop destroy detaileddetect device devote diagnosedictate diet dilemma diminishdining diploma disasterdiscuss disease dish dismiss display distancedive divorce documentdomain domesticdominantdough downtowndragon dramaticdream dress drift drink drove drug dryer ducklingduke durationdwarf dynamic early earth easel easy echo eclipse ecology edge editor educate either elbow elder electionelegant element elephantelevatorelite else email emerald emissionemperor emphasisemployerempty ending endless endorse enemy energy enforce engage enjoy enlarge entranceenvelopeenvy epidemicepisode equationequip eraser erode escape estate estimateevaluateevening evidenceevil evoke exact example exceed exchangeexclude excuse execute exerciseexhaust exotic expand expect explain express extend extra eyebrow facilityfact failure faint fake false family famous fancy fangs fantasy fatal fatigue favoritefawn fiber fiction filter finance findingsfinger firefly firm fiscal fishing fitness flame flash flavor flea flexibleflip float floral fluff focus forbid force forecastforget formal fortune forward founder fractionfragmentfrequentfreshmanfriar fridge friendlyfrost froth frozen fumes funding furl fused galaxy game garbage garden garlic gasolinegather general genius genre genuine geology gesture glad glance glasses glen glimpse goat golden graduategrant grasp gravity gray greatestgrief grill grin grocery gross group grownup grumpy guard guest guilt guitar gums hairy hamster hand hanger harvest have havoc hawk hazard headset health hearing heat helpful herald herd hesitatehobo holiday holy home hormone hospitalhour huge human humidityhunting husband hush husky hybrid idea identifyidle image impact imply improve impulse include income increaseindex indicateindustryinfant inform inherit injury inmate insect inside install intend intimateinvasioninvolve iris island isolate item ivory jacket jerky jewelry join judicialjuice jump junctionjunior junk jury justice kernel keyboardkidney kind kitchen knife knit laden ladle ladybug lair lamp languagelarge laser laundry lawsuit leader leaf learn leaves lecture legal legend legs lend length level liberty library license lift likely lilac lily lips liquid listen literaryliving lizard loan lobe locationlosing loud loyalty luck lunar lunch lungs luxury lying lyrics machine magazinemaiden mailman main makeup making mama manager mandate mansion manual marathonmarch market marvel mason materialmath maximum mayor meaning medal medical member memory mental merchantmerit method metric midst mild militarymineral ministermiracle mixed mixture mobile modern modify moisturemoment morning mortgagemother mountainmouse move much mule multiplemuscle museum music mustang nail nationalnecklacenegativenervous network news nuclear numb numerousnylon oasis obesity object observe obtain ocean often olympic omit oral orange orbit order ordinaryorganizeounce oven overall owner paces pacific package paid paintingpajamas pancake pants papa paper parcel parking party patent patrol payment payroll peacefulpeanut peasant pecan penalty pencil percent perfect permit petitionphantom pharmacyphoto phrase physics pickup picture piece pile pink pipelinepistol pitch plains plan plastic platformplayoff pleasureplot plunge practiceprayer preach predatorpregnantpremium prepare presenceprevent priest primary priorityprisonerprivacy prize problem process profile program promise prospectprovide prune public pulse pumps punish puny pupal purchasepurple python quantityquarter quick quiet race racism radar railroadrainbow raisin random ranked rapids raspy reactionrealize rebound rebuild recall receiverrecover regret regular reject relate rememberremind remove render repair repeat replace require rescue researchresidentresponseresult retailerretreat reunion revenue review reward rhyme rhythm rich rival river robin rocky romanticromp roster round royal ruin ruler rumor sack safari salary salon salt satisfy satoshi saver says scandal scared scatter scene scholar science scout scramblescrew script scroll seafood season secret securitysegment senior shadow shaft shame shaped sharp shelter sheriff short should shrimp sidewalksilent silver similar simple single sister skin skunk slap slavery sled slice slim slow slush smart smear smell smirk smith smoking smug snake snapshotsniff society softwaresoldier solutionsoul source space spark speak species spellingspend spew spider spill spine spirit spit spray sprinklesquare squeeze stadium staff standardstartingstation stay steady step stick stilt story strategystrike style subject submit sugar suitablesunlightsuperiorsurface surprisesurvive sweater swimmingswing switch symbolicsympathysyndromesystem tackle tactics tadpole talent task taste taught taxi teacher teammateteaspoontemple tenant tendencytension terminaltestify texture thank that theater theory therapy thorn threatenthumb thunder ticket tidy timber timely ting tofu togethertoleratetotal toxic tracks traffic trainingtransfertrash travelertreat trend trial tricycletrip triumph trouble true trust twice twin type typical ugly ultimateumbrellauncover undergo unfair unfold unhappy union universeunkind unknown unusual unwrap upgrade upstairsusernameusher usual valid valuablevampire vanish various vegan velvet venture verdict verify very veteran vexed victim video view vintage violenceviral visitor visual vitaminsvocal voice volume voter voting walnut warmth warn watch wavy wealthy weapon webcam welcome welfare western width wildlifewindow wine wirelesswisdom withdrawwits wolf woman work worthy wrap wrist writing wrote year yelp yield yoga zero " diff --git a/core/src/trezor/messages/ResetDevice.py b/core/src/trezor/messages/ResetDevice.py index 8c41eafc32..f8774381a2 100644 --- a/core/src/trezor/messages/ResetDevice.py +++ b/core/src/trezor/messages/ResetDevice.py @@ -17,6 +17,7 @@ class ResetDevice(p.MessageType): u2f_counter: int = None, skip_backup: bool = None, no_backup: bool = None, + slip39: bool = None, ) -> None: self.display_random = display_random self.strength = strength @@ -27,6 +28,7 @@ class ResetDevice(p.MessageType): self.u2f_counter = u2f_counter self.skip_backup = skip_backup self.no_backup = no_backup + self.slip39 = slip39 @classmethod def get_fields(cls): @@ -40,4 +42,5 @@ class ResetDevice(p.MessageType): 7: ('u2f_counter', p.UVarintType, 0), 8: ('skip_backup', p.BoolType, 0), 9: ('no_backup', p.BoolType, 0), + 10: ('slip39', p.BoolType, 0), } diff --git a/core/src/trezor/ui/checklist.py b/core/src/trezor/ui/checklist.py new file mode 100644 index 0000000000..27c9933ae5 --- /dev/null +++ b/core/src/trezor/ui/checklist.py @@ -0,0 +1,55 @@ +from micropython import const + +from trezor import ui +from trezor.ui import text + +_CHECKLIST_MAX_LINES = const(5) +_CHECKLIST_OFFSET_X = const(24) + + +class Checklist(ui.Control): + def __init__(self, title, icon): + self.title = title + self.icon = icon + self.choices = [] + self.words = [] + self.active = 0 + self.repaint = False + + def add(self, choice): + self.choices.append(choice) + + def select(self, active): + self.active = active + + def process(self): + w = self.words + w.clear() + for index, choice in enumerate(self.choices): + if index < self.active: + w.append(ui.BOLD) + w.append(ui.GREEN) + elif index == self.active: + w.append(ui.BOLD) + w.append(ui.FG) + else: # index > self.active + w.append(ui.NORMAL) + w.append(ui.GREY) + if isinstance(choice, str): + w.append(choice) + else: # choice is iterable + w.extend(choice) + w.append(text.BR) + self.words = w + self.repaint = True + + def on_render(self): + if self.repaint: + ui.header(self.title, self.icon) + text.render_text( + self.words, + new_lines=False, # we are adding line breaks manually + max_lines=_CHECKLIST_MAX_LINES, + offset_x=_CHECKLIST_OFFSET_X, + ) + self.repaint = False diff --git a/core/src/trezor/ui/confirm.py b/core/src/trezor/ui/confirm.py index 1be20caa8d..b28d1438c3 100644 --- a/core/src/trezor/ui/confirm.py +++ b/core/src/trezor/ui/confirm.py @@ -19,12 +19,15 @@ class Confirm(ui.Layout): confirm_style=DEFAULT_CONFIRM_STYLE, cancel=DEFAULT_CANCEL, cancel_style=DEFAULT_CANCEL_STYLE, + major_confirm=False, ): self.content = content if confirm is not None: if cancel is None: area = ui.grid(4, n_x=1) + elif major_confirm: + area = ui.grid(13, cells_x=2) else: area = ui.grid(9, n_x=2) self.confirm = Button(area, confirm, confirm_style) @@ -35,6 +38,8 @@ class Confirm(ui.Layout): if cancel is not None: if confirm is None: area = ui.grid(4, n_x=1) + elif major_confirm: + area = ui.grid(12, cells_x=1) else: area = ui.grid(8, n_x=2) self.cancel = Button(area, cancel, cancel_style) diff --git a/core/src/trezor/ui/info.py b/core/src/trezor/ui/info.py new file mode 100644 index 0000000000..07fb77f312 --- /dev/null +++ b/core/src/trezor/ui/info.py @@ -0,0 +1,63 @@ +from trezor import res, ui +from trezor.ui.button import Button, ButtonConfirm +from trezor.ui.confirm import CONFIRMED +from trezor.ui.text import TEXT_LINE_HEIGHT, TEXT_MARGIN_LEFT, render_text + + +class DefaultInfoConfirm: + + fg_color = ui.LIGHT_GREY + bg_color = ui.BLACKISH + + class button(ButtonConfirm): + class normal(ButtonConfirm.normal): + border_color = ui.BLACKISH + + class disabled(ButtonConfirm.disabled): + border_color = ui.BLACKISH + + +class InfoConfirm(ui.Layout): + DEFAULT_CONFIRM = res.load(ui.ICON_CONFIRM) + DEFAULT_STYLE = DefaultInfoConfirm + + def __init__(self, text, confirm=DEFAULT_CONFIRM, style=DEFAULT_STYLE): + self.text = text.split() + self.style = style + panel_area = ui.grid(0, n_x=1, n_y=1) + self.panel_area = panel_area + confirm_area = ui.grid(4, n_x=1) + self.confirm = Button(confirm_area, confirm, style.button) + self.confirm.on_click = self.on_confirm + self.repaint = True + + def dispatch(self, event, x, y): + if event == ui.RENDER: + self.on_render() + self.confirm.dispatch(event, x, y) + + def on_render(self): + if self.repaint: + x, y, w, h = self.panel_area + fg_color = self.style.fg_color + bg_color = self.style.bg_color + + # render the background panel + ui.display.bar_radius(x, y, w, h, bg_color, ui.BG, ui.RADIUS) + + # render the info text + render_text( + self.text, + new_lines=False, + max_lines=6, + offset_y=y + TEXT_LINE_HEIGHT, + offset_x=x + TEXT_MARGIN_LEFT - ui.VIEWX, + offset_x_max=x + w - ui.VIEWX, + fg=fg_color, + bg=bg_color, + ) + + self.repaint = False + + def on_confirm(self): + raise ui.Result(CONFIRMED) diff --git a/core/src/trezor/ui/loader.py b/core/src/trezor/ui/loader.py index 1e0fd70368..fd992fbb53 100644 --- a/core/src/trezor/ui/loader.py +++ b/core/src/trezor/ui/loader.py @@ -77,6 +77,26 @@ class Loader(ui.Control): self.start_ms = None self.stop_ms = None self.on_start() + if r == target: + self.on_finish() def on_start(self): pass + + def on_finish(self): + pass + + +class LoadingAnimation(ui.Layout): + def __init__(self, style=LoaderDefault): + self.loader = Loader(style) + self.loader.on_finish = self.on_finish + self.loader.start() + + def dispatch(self, event, x, y): + if not self.loader.elapsed_ms(): + self.loader.start() + self.loader.dispatch(event, x, y) + + def on_finish(self): + raise ui.Result(None) diff --git a/core/src/trezor/ui/shamir.py b/core/src/trezor/ui/shamir.py new file mode 100644 index 0000000000..5a7bc91ac9 --- /dev/null +++ b/core/src/trezor/ui/shamir.py @@ -0,0 +1,49 @@ +from trezor import ui +from trezor.ui.button import Button +from trezor.ui.text import LABEL_CENTER, Label + + +class NumInput(ui.Control): + def __init__(self, count=5, max_count=16, min_count=1): + self.count = count + self.max_count = max_count + self.min_count = min_count + + self.minus = Button(ui.grid(3), "-") + self.minus.on_click = self.on_minus + self.plus = Button(ui.grid(5), "+") + self.plus.on_click = self.on_plus + self.text = Label(ui.grid(4), "", LABEL_CENTER, ui.BOLD) + + self.edit(count) + + def dispatch(self, event, x, y): + self.minus.dispatch(event, x, y) + self.plus.dispatch(event, x, y) + self.text.dispatch(event, x, y) + + def on_minus(self): + self.edit(self.count - 1) + + def on_plus(self): + self.edit(self.count + 1) + + def edit(self, count): + count = max(count, self.min_count) + count = min(count, self.max_count) + if self.count != count: + self.on_change(count) + self.count = count + self.text.content = str(count) + self.text.repaint = True + if self.count == self.min_count: + self.minus.disable() + else: + self.minus.enable() + if self.count == self.max_count: + self.plus.disable() + else: + self.plus.enable() + + def on_change(self, count): + pass diff --git a/core/src/trezor/ui/text.py b/core/src/trezor/ui/text.py index 0746001ba0..f99c9059c3 100644 --- a/core/src/trezor/ui/text.py +++ b/core/src/trezor/ui/text.py @@ -13,15 +13,21 @@ BR = const(-256) BR_HALF = const(-257) -def render_text(words: list, new_lines: bool, max_lines: int) -> None: +def render_text( + words: list, + new_lines: bool, + max_lines: int, + font: int = ui.NORMAL, + fg: int = ui.FG, + bg: int = ui.BG, + offset_x: int = TEXT_MARGIN_LEFT, + offset_y: int = TEXT_HEADER_HEIGHT + TEXT_LINE_HEIGHT, + offset_x_max: int = ui.WIDTH, +) -> None: # initial rendering state - font = ui.NORMAL - fg = ui.FG - bg = ui.BG - offset_x = TEXT_MARGIN_LEFT - offset_y = TEXT_HEADER_HEIGHT + TEXT_LINE_HEIGHT - OFFSET_X_MAX = ui.WIDTH - OFFSET_Y_MAX = TEXT_HEADER_HEIGHT + TEXT_LINE_HEIGHT * max_lines + INITIAL_OFFSET_X = offset_x + offset_y_max = offset_y * max_lines + FONTS = (ui.NORMAL, ui.BOLD, ui.MONO, ui.MONO_BOLD) # sizes of common glyphs @@ -35,10 +41,10 @@ def render_text(words: list, new_lines: bool, max_lines: int) -> None: if isinstance(word, int): if word is BR or word is BR_HALF: # line break or half-line break - if offset_y >= OFFSET_Y_MAX: + if offset_y >= offset_y_max: ui.display.text(offset_x, offset_y, "...", ui.BOLD, ui.GREY, bg) return - offset_x = TEXT_MARGIN_LEFT + offset_x = INITIAL_OFFSET_X offset_y += TEXT_LINE_HEIGHT if word is BR else TEXT_LINE_HEIGHT_HALF elif word in FONTS: # change of font style @@ -50,22 +56,22 @@ def render_text(words: list, new_lines: bool, max_lines: int) -> None: width = ui.display.text_width(word, font) - while offset_x + width > OFFSET_X_MAX or ( - has_next_word and offset_y >= OFFSET_Y_MAX + while offset_x + width > offset_x_max or ( + has_next_word and offset_y >= offset_y_max ): - beginning_of_line = offset_x == TEXT_MARGIN_LEFT - word_fits_in_one_line = width < (OFFSET_X_MAX - TEXT_MARGIN_LEFT) + beginning_of_line = offset_x == INITIAL_OFFSET_X + word_fits_in_one_line = width < (offset_x_max - INITIAL_OFFSET_X) if ( - offset_y < OFFSET_Y_MAX + offset_y < offset_y_max and word_fits_in_one_line and not beginning_of_line ): # line break - offset_x = TEXT_MARGIN_LEFT + offset_x = INITIAL_OFFSET_X offset_y += TEXT_LINE_HEIGHT break # word split - if offset_y < OFFSET_Y_MAX: + if offset_y < offset_y_max: split = "-" splitw = DASH else: @@ -75,7 +81,7 @@ def render_text(words: list, new_lines: bool, max_lines: int) -> None: for index in range(len(word) - 1, 0, -1): letter = word[index] width -= ui.display.text_width(letter, font) - if offset_x + width + splitw < OFFSET_X_MAX: + if offset_x + width + splitw < offset_x_max: break else: index = 0 @@ -84,9 +90,9 @@ def render_text(words: list, new_lines: bool, max_lines: int) -> None: ui.display.text(offset_x, offset_y, span, font, fg, bg) ui.display.text(offset_x + width, offset_y, split, ui.BOLD, ui.GREY, bg) # line break - if offset_y >= OFFSET_Y_MAX: + if offset_y >= offset_y_max: return - offset_x = TEXT_MARGIN_LEFT + offset_x = INITIAL_OFFSET_X offset_y += TEXT_LINE_HEIGHT # continue with the rest word = word[index:] @@ -97,10 +103,10 @@ def render_text(words: list, new_lines: bool, max_lines: int) -> None: if new_lines and has_next_word: # line break - if offset_y >= OFFSET_Y_MAX: + if offset_y >= offset_y_max: ui.display.text(offset_x, offset_y, "...", ui.BOLD, ui.GREY, bg) return - offset_x = TEXT_MARGIN_LEFT + offset_x = INITIAL_OFFSET_X offset_y += TEXT_LINE_HEIGHT else: # shift cursor @@ -158,3 +164,31 @@ class Text(ui.Control): ) render_text(self.content, self.new_lines, self.max_lines) self.repaint = False + + +LABEL_LEFT = const(0) +LABEL_CENTER = const(1) +LABEL_RIGHT = const(2) + + +class Label(ui.Control): + def __init__(self, area, content, align=LABEL_LEFT, style=ui.NORMAL): + self.area = area + self.content = content + self.align = align + self.style = style + self.repaint = True + + def on_render(self): + if self.repaint: + align = self.align + ax, ay, aw, ah = self.area + tx = ax + aw // 2 + ty = ay + ah // 2 + 8 + if align is LABEL_LEFT: + ui.display.text_left(tx, ty, self.content, self.style, ui.FG, ui.BG) + elif align is LABEL_CENTER: + ui.display.text_center(tx, ty, self.content, self.style, ui.FG, ui.BG) + elif align is LABEL_RIGHT: + ui.display.text_right(tx, ty, self.content, self.style, ui.FG, ui.BG) + self.repaint = False diff --git a/core/src/trezor/ui/word_select.py b/core/src/trezor/ui/word_select.py index ee32095508..358c2f7056 100644 --- a/core/src/trezor/ui/word_select.py +++ b/core/src/trezor/ui/word_select.py @@ -1,22 +1,30 @@ from trezor import ui from trezor.ui.button import Button +# todo improve? + class WordSelector(ui.Layout): def __init__(self, content): self.content = content - self.w12 = Button(ui.grid(6, n_y=4, n_x=3, cells_y=2), "12") + self.w12 = Button(ui.grid(6, n_y=4), "12") self.w12.on_click = self.on_w12 - self.w18 = Button(ui.grid(7, n_y=4, n_x=3, cells_y=2), "18") + self.w18 = Button(ui.grid(7, n_y=4), "18") self.w18.on_click = self.on_w18 - self.w24 = Button(ui.grid(8, n_y=4, n_x=3, cells_y=2), "24") + self.w20 = Button(ui.grid(8, n_y=4), "20") + self.w20.on_click = self.on_w20 + self.w24 = Button(ui.grid(9, n_y=4), "24") self.w24.on_click = self.on_w24 + self.w33 = Button(ui.grid(10, n_y=4), "33") + self.w33.on_click = self.on_w33 def dispatch(self, event, x, y): self.content.dispatch(event, x, y) self.w12.dispatch(event, x, y) self.w18.dispatch(event, x, y) + self.w20.dispatch(event, x, y) self.w24.dispatch(event, x, y) + self.w33.dispatch(event, x, y) def on_w12(self): raise ui.Result(12) @@ -24,5 +32,11 @@ class WordSelector(ui.Layout): def on_w18(self): raise ui.Result(18) + def on_w20(self): + raise ui.Result(20) + def on_w24(self): raise ui.Result(24) + + def on_w33(self): + raise ui.Result(33) diff --git a/core/tests/test_trezor.crypto.slip39.py b/core/tests/test_trezor.crypto.slip39.py index 937f4aea37..057203daa4 100644 --- a/core/tests/test_trezor.crypto.slip39.py +++ b/core/tests/test_trezor.crypto.slip39.py @@ -25,12 +25,15 @@ class TestCryptoSlip39(unittest.TestCase): MS = b"ABCDEFGHIJKLMNOP" def test_basic_sharing_random(self): - mnemonics = slip39.generate_mnemonics_random(1, [(3, 5)])[0] + ms = random.bytes(32) + _, mnemonics = slip39.generate_mnemonics_from_data(ms, 1, [(3, 5)]) + mnemonics = mnemonics[0] self.assertEqual(slip39.combine_mnemonics(mnemonics[:3]), slip39.combine_mnemonics(mnemonics[2:])) def test_basic_sharing_fixed(self): - mnemonics = slip39.generate_mnemonics(1, [(3, 5)], self.MS)[0] + _, mnemonics = slip39.generate_mnemonics_from_data(self.MS, 1, [(3, 5)]) + mnemonics = mnemonics[0] identifier, exponent, ems = slip39.combine_mnemonics(mnemonics[:3]) self.assertEqual(slip39.decrypt(identifier, exponent, ems, b""), self.MS) self.assertEqual(slip39.combine_mnemonics(mnemonics[1:4])[2], ems) @@ -39,19 +42,22 @@ class TestCryptoSlip39(unittest.TestCase): def test_passphrase(self): - mnemonics = slip39.generate_mnemonics(1, [(3, 5)], self.MS, b"TREZOR")[0] + _, mnemonics = slip39.generate_mnemonics_from_data(self.MS, 1, [(3, 5)], b"TREZOR") + mnemonics = mnemonics[0] identifier, exponent, ems = slip39.combine_mnemonics(mnemonics[1:4]) self.assertEqual(slip39.decrypt(identifier, exponent, ems, b"TREZOR"), self.MS) self.assertNotEqual(slip39.decrypt(identifier, exponent, ems, b""), self.MS) def test_iteration_exponent(self): - mnemonics = slip39.generate_mnemonics(1, [(3, 5)], self.MS, b"TREZOR", 1)[0] + _, mnemonics = slip39.generate_mnemonics_from_data(self.MS, 1, [(3, 5)], b"TREZOR", 1) + mnemonics = mnemonics[0] identifier, exponent, ems = slip39.combine_mnemonics(mnemonics[1:4]) self.assertEqual(slip39.decrypt(identifier, exponent, ems, b"TREZOR"), self.MS) self.assertNotEqual(slip39.decrypt(identifier, exponent, ems, b""), self.MS) - mnemonics = slip39.generate_mnemonics(1, [(3, 5)], self.MS, b"TREZOR", 2)[0] + _, mnemonics = slip39.generate_mnemonics_from_data(self.MS, 1, [(3, 5)], b"TREZOR", 2) + mnemonics = mnemonics[0] identifier, exponent, ems = slip39.combine_mnemonics(mnemonics[1:4]) self.assertEqual(slip39.decrypt(identifier, exponent, ems, b"TREZOR"), self.MS) self.assertNotEqual(slip39.decrypt(identifier, exponent, ems, b""), self.MS) @@ -61,8 +67,8 @@ class TestCryptoSlip39(unittest.TestCase): group_threshold = 2 group_sizes = (5, 3, 5, 1) member_thresholds = (3, 2, 2, 1) - mnemonics = slip39.generate_mnemonics( - group_threshold, list(zip(member_thresholds, group_sizes)), self.MS + _, mnemonics = slip39.generate_mnemonics_from_data( + self.MS, group_threshold, list(zip(member_thresholds, group_sizes)) ) # Test all valid combinations of mnemonics. @@ -93,8 +99,8 @@ class TestCryptoSlip39(unittest.TestCase): group_threshold = 1 group_sizes = (5, 3, 5, 1) member_thresholds = (3, 2, 2, 1) - mnemonics = slip39.generate_mnemonics( - group_threshold, list(zip(member_thresholds, group_sizes)), self.MS + _, mnemonics = slip39.generate_mnemonics_from_data( + self.MS, group_threshold, list(zip(member_thresholds, group_sizes)) ) # Test all valid combinations of mnemonics. @@ -108,8 +114,8 @@ class TestCryptoSlip39(unittest.TestCase): def test_all_groups_exist(self): for group_threshold in (1, 2, 5): - mnemonics = slip39.generate_mnemonics( - group_threshold, [(3, 5), (1, 1), (2, 3), (2, 5), (3, 5)], self.MS + _, mnemonics = slip39.generate_mnemonics_from_data( + self.MS, group_threshold, [(3, 5), (1, 1), (2, 3), (2, 5), (3, 5)] ) self.assertEqual(len(mnemonics), 5) self.assertEqual(len(sum(mnemonics, [])), 19) @@ -118,31 +124,31 @@ class TestCryptoSlip39(unittest.TestCase): def test_invalid_sharing(self): # Short master secret. with self.assertRaises(ValueError): - slip39.generate_mnemonics(1, [(2, 3)], self.MS[:14]) + slip39.generate_mnemonics_from_data(self.MS[:14], 1, [(2, 3)]) # Odd length master secret. with self.assertRaises(ValueError): - slip39.generate_mnemonics(1, [(2, 3)], self.MS + b"X") + slip39.generate_mnemonics_from_data(self.MS + b"X", 1, [(2, 3)]) # Group threshold exceeds number of groups. with self.assertRaises(ValueError): - slip39.generate_mnemonics(3, [(3, 5), (2, 5)], self.MS) + slip39.generate_mnemonics_from_data(self.MS, 3, [(3, 5), (2, 5)]) # Invalid group threshold. with self.assertRaises(ValueError): - slip39.generate_mnemonics(0, [(3, 5), (2, 5)], self.MS) + slip39.generate_mnemonics_from_data(self.MS, 0, [(3, 5), (2, 5)]) # Member threshold exceeds number of members. with self.assertRaises(ValueError): - slip39.generate_mnemonics(2, [(3, 2), (2, 5)], self.MS) + slip39.generate_mnemonics_from_data(self.MS, 2, [(3, 2), (2, 5)]) # Invalid member threshold. with self.assertRaises(ValueError): - slip39.generate_mnemonics(2, [(0, 2), (2, 5)], self.MS) + slip39.generate_mnemonics_from_data(self.MS, 2, [(0, 2), (2, 5)]) # Group with multiple members and threshold 1. with self.assertRaises(ValueError): - slip39.generate_mnemonics(2, [(3, 5), (1, 3), (2, 5)], self.MS) + slip39.generate_mnemonics_from_data(self.MS, 2, [(3, 5), (1, 3), (2, 5)]) def test_vectors(self): diff --git a/python/trezorlib/coins.json b/python/trezorlib/coins.json index a9da0f8d19..b4663359ff 100644 --- a/python/trezorlib/coins.json +++ b/python/trezorlib/coins.json @@ -1 +1 @@ -[{"address_type": 0, "address_type_p2sh": 5, "bech32_prefix": "bc", "bip115": false, "bitcore": [], "blockbook": ["https://btc1.trezor.io", "https://btc2.trezor.io", "https://btc3.trezor.io", "https://btc4.trezor.io", "https://btc5.trezor.io"], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Bitcoin", "coin_name": "Bitcoin", "coin_shortcut": "BTC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 70, "High": 200, "Low": 10, "Normal": 140}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/bitcoin/bitcoin", "hash_genesis_block": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", "key": "bitcoin:BTC", "maintainer": "Pavol Rusnak ", "max_address_length": 34, "maxfee_kb": 2000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Bitcoin", "segwit": true, "shortcut": "BTC", "signed_message_header": "Bitcoin Signed Message:\n", "slip44": 0, "support": {"connect": true, "trezor1": "1.5.2", "trezor2": "2.0.5", "webwallet": true}, "uri_prefix": "bitcoin", "website": "https://bitcoin.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 111, "address_type_p2sh": 196, "bech32_prefix": "tb", "bip115": false, "bitcore": [], "blockbook": ["https://tbtc1.trezor.io", "https://tbtc2.trezor.io"], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Testnet", "coin_name": "Testnet", "coin_shortcut": "TEST", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/bitcoin/bitcoin", "hash_genesis_block": "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943", "key": "bitcoin:TEST", "maintainer": "Pavol Rusnak ", "max_address_length": 34, "maxfee_kb": 10000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Testnet", "segwit": true, "shortcut": "TEST", "signed_message_header": "Bitcoin Signed Message:\n", "slip44": 1, "support": {"connect": true, "trezor1": "1.5.2", "trezor2": "2.0.5", "webwallet": true}, "uri_prefix": "bitcoin", "website": "https://bitcoin.org", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": 73342198, "xpub_magic_segwit_p2sh": 71979618}, {"address_type": 53, "address_type_p2sh": 55, "bech32_prefix": "acm", "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Actinium", "coin_name": "Actinium", "coin_shortcut": "ACM", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 1000}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/Actinium-project/Actinium", "hash_genesis_block": "28d77872e23714562f49a1be792c276623c1bbe3fdcf21b6035cfde78b00b824", "key": "bitcoin:ACM", "maintainer": "Harris Brakmic ", "max_address_length": 34, "maxfee_kb": 40000000, "min_address_length": 27, "minfee_kb": 100000, "name": "Actinium", "segwit": true, "shortcut": "ACM", "signed_message_header": "Actinium Signed Message:\n", "slip44": 228, "support": {"connect": true, "trezor1": "1.7.2", "trezor2": "2.0.10", "webwallet": true}, "uri_prefix": "actinium", "website": "https://actinium.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 55, "address_type_p2sh": 16, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Axe", "coin_name": "Axe", "coin_shortcut": "AXE", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 5460, "force_bip143": false, "fork_id": null, "github": "https://github.com/axerunners/axe", "hash_genesis_block": "00000c33631ca6f2f61368991ce2dc03306b5bb50bf7cede5cfbba6db38e52e6", "key": "bitcoin:AXE", "maintainer": "Kirill Orlov ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 1000, "name": "Axe", "segwit": false, "shortcut": "AXE", "signed_message_header": "DarkCoin Signed Message:\n", "slip44": 4242, "support": {"connect": true, "trezor1": "1.7.3", "trezor2": "2.0.11", "webwallet": false}, "uri_prefix": "axe", "website": "https://axerunners.com", "xprv_magic": 50221816, "xpub_magic": 50221772, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 25, "address_type_p2sh": 85, "bech32_prefix": "bm", "bip115": false, "bitcore": [], "blockbook": ["https://bellcoin-blockbook.ilmango.work", "https://bell.blockbook.ovh"], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Bellcoin", "coin_name": "Bellcoin", "coin_shortcut": "BELL", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 20}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/bellcoin-org/bellcoin", "hash_genesis_block": "000008f3b6bd10c2d03b06674a006b8d9731f6cb58179ef1eee008cee2209603", "key": "bitcoin:BELL", "maintainer": "ilmango-doge ", "max_address_length": 34, "maxfee_kb": 1000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Bellcoin", "segwit": true, "shortcut": "BELL", "signed_message_header": "Bellcoin Signed Message:\n", "slip44": 25252, "support": {"connect": false, "trezor1": "1.8.2", "trezor2": "2.1.1", "webwallet": false}, "uri_prefix": "bellcoin", "website": "https://bellcoin.web4u.jp", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 230, "address_type_p2sh": 235, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "BitCash", "coin_name": "BitCash", "coin_shortcut": "BITC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 70, "High": 200, "Low": 10, "Normal": 140}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/WillyTheCat/BitCash", "hash_genesis_block": "7d57d87ff3c15a521530af60edee1887fba9c193eb518face926785c4cd8f4f1", "key": "bitcoin:BITC", "maintainer": "Christian Kassler ", "max_address_length": 53, "maxfee_kb": 30000000, "min_address_length": 52, "minfee_kb": 1000, "name": "BitCash", "segwit": false, "shortcut": "BITC", "signed_message_header": "Bitcash Signed Message:\n", "slip44": 230, "support": {"connect": true, "trezor1": "1.7.2", "trezor2": "2.0.10", "webwallet": false}, "uri_prefix": "bitcash", "website": "https://www.choosebitcash.com", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 81, "address_type_p2sh": 5, "bech32_prefix": "bz", "bip115": false, "bitcore": ["https://insight.bitzeny.jp", "https://zeny.insight.monaco-ex.org"], "blockbook": ["https://zny.blockbook.ovh"], "blocktime_seconds": 90, "cashaddr_prefix": null, "coin_label": "BitZeny", "coin_name": "BitZeny", "coin_shortcut": "ZNY", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 20}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/BitzenyCoreDevelopers/bitzeny", "hash_genesis_block": "000009f7e55e9e3b4781e22bd87a7cfa4acada9e4340d43ca738bf4e9fb8f5ce", "key": "bitcoin:ZNY", "maintainer": "y-chan ", "max_address_length": 34, "maxfee_kb": 1000000, "min_address_length": 27, "minfee_kb": 1000, "name": "BitZeny", "segwit": true, "shortcut": "ZNY", "signed_message_header": "BitZeny Signed Message:\n", "slip44": 123, "support": {"connect": false, "trezor1": "1.8.2", "trezor2": "2.1.1", "webwallet": false}, "uri_prefix": "bitzeny", "website": "https://bitzeny.tech", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 25, "address_type_p2sh": 5, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 300, "cashaddr_prefix": null, "coin_label": "Bitcloud", "coin_name": "Bitcloud", "coin_shortcut": "BTDX", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 5460, "force_bip143": false, "fork_id": null, "github": "https://github.com/LIMXTEC/Bitcloud", "hash_genesis_block": "000002d56463941c20eae5cb474cc805b646515d18bc7dc222a0885b206eadb0", "key": "bitcoin:BTDX", "maintainer": "limxdev ", "max_address_length": 34, "maxfee_kb": 1000000, "min_address_length": 27, "minfee_kb": 10000, "name": "Bitcloud", "segwit": false, "shortcut": "BTDX", "signed_message_header": "Diamond Signed Message:\n", "slip44": 218, "support": {"connect": true, "trezor1": "1.7.2", "trezor2": "2.0.10", "webwallet": false}, "uri_prefix": "bitcloud", "website": "https://bit-cloud.info", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 0, "address_type_p2sh": 5, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://bch1.trezor.io", "https://bch2.trezor.io", "https://bch3.trezor.io", "https://bch4.trezor.io", "https://bch5.trezor.io"], "blocktime_seconds": 600, "cashaddr_prefix": "bitcoincash", "coin_label": "Bitcoin Cash", "coin_name": "Bcash", "coin_shortcut": "BCH", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 70, "High": 200, "Low": 10, "Normal": 140}, "dust_limit": 546, "force_bip143": true, "fork_id": 0, "github": "https://github.com/Bitcoin-ABC/bitcoin-abc", "hash_genesis_block": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", "key": "bitcoin:BCH", "maintainer": "Jochen Hoenicke ", "max_address_length": 34, "maxfee_kb": 500000, "min_address_length": 27, "minfee_kb": 1000, "name": "Bitcoin Cash", "segwit": false, "shortcut": "BCH", "signed_message_header": "Bitcoin Signed Message:\n", "slip44": 145, "support": {"connect": true, "trezor1": "1.6.2", "trezor2": "2.0.7", "webwallet": true}, "uri_prefix": "bitcoincash", "website": "https://www.bitcoincash.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 111, "address_type_p2sh": 196, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 600, "cashaddr_prefix": "bchtest", "coin_label": "Bitcoin Cash Testnet", "coin_name": "Bcash Testnet", "coin_shortcut": "TBCH", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": true, "fork_id": 0, "github": "https://github.com/Bitcoin-ABC/bitcoin-abc", "hash_genesis_block": "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943", "key": "bitcoin:TBCH", "maintainer": "Jochen Hoenicke ", "max_address_length": 34, "maxfee_kb": 10000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Bitcoin Cash Testnet", "segwit": false, "shortcut": "TBCH", "signed_message_header": "Bitcoin Signed Message:\n", "slip44": 1, "support": {"connect": true, "trezor1": "1.6.2", "trezor2": "2.0.7", "webwallet": false}, "uri_prefix": "bitcoincash", "website": "https://www.bitcoincash.org", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 38, "address_type_p2sh": 23, "bech32_prefix": "btg", "bip115": false, "bitcore": [], "blockbook": ["https://btg1.trezor.io", "https://btg2.trezor.io", "https://btg3.trezor.io", "https://btg4.trezor.io", "https://btg5.trezor.io"], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Bitcoin Gold", "coin_name": "Bgold", "coin_shortcut": "BTG", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 70, "High": 200, "Low": 10, "Normal": 140}, "dust_limit": 546, "force_bip143": true, "fork_id": 79, "github": "https://github.com/BTCGPU/BTCGPU", "hash_genesis_block": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", "key": "bitcoin:BTG", "maintainer": "Saleem Rashid ", "max_address_length": 34, "maxfee_kb": 500000, "min_address_length": 27, "minfee_kb": 1000, "name": "Bitcoin Gold", "segwit": true, "shortcut": "BTG", "signed_message_header": "Bitcoin Gold Signed Message:\n", "slip44": 156, "support": {"connect": true, "trezor1": "1.6.2", "trezor2": "2.0.7", "webwallet": true}, "uri_prefix": "bitcoingold", "website": "https://bitcoingold.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 111, "address_type_p2sh": 196, "bech32_prefix": "tbtg", "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Bitcoin Gold Testnet", "coin_name": "Bgold Testnet", "coin_shortcut": "TBTG", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 70, "High": 200, "Low": 10, "Normal": 140}, "dust_limit": 546, "force_bip143": true, "fork_id": 79, "github": "https://github.com/BTCGPU/BTCGPU", "hash_genesis_block": "00000000e0781ebe24b91eedc293adfea2f557b53ec379e78959de3853e6f9f6", "key": "bitcoin:TBTG", "maintainer": "The Bitcoin Gold Developers ", "max_address_length": 34, "maxfee_kb": 500000, "min_address_length": 27, "minfee_kb": 1000, "name": "Bitcoin Gold Testnet", "segwit": true, "shortcut": "TBTG", "signed_message_header": "Bitcoin Gold Signed Message:\n", "slip44": 156, "support": {"connect": true, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "bitcoingold", "website": "https://bitcoingold.org", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": 73342198, "xpub_magic_segwit_p2sh": 71979618}, {"address_type": 4901, "address_type_p2sh": 5039, "bech32_prefix": null, "bip115": false, "bitcore": ["https://explorer.btcprivate.org"], "blockbook": [], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Bitcoin Private", "coin_name": "Bprivate", "coin_shortcut": "BTCP", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": 42, "github": "https://github.com/BTCPrivate/BitcoinPrivate", "hash_genesis_block": "0007104ccda289427919efc39dc9e4d499804b7bebc22df55f8b834301260602", "key": "bitcoin:BTCP", "maintainer": "Chris Sulmone ", "max_address_length": 95, "maxfee_kb": 1000000, "min_address_length": 35, "minfee_kb": 1000, "name": "Bitcoin Private", "segwit": false, "shortcut": "BTCP", "signed_message_header": "BitcoinPrivate Signed Message:\n", "slip44": 183, "support": {"connect": true, "trezor1": "1.6.2", "trezor2": "2.0.7", "webwallet": true}, "uri_prefix": "bitcoinprivate", "website": "https://btcprivate.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 61, "address_type_p2sh": 123, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://blockbook1.bitcoinrh.org", "https://blockbook2.bitcoinrh.org"], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Bitcoin Rhodium", "coin_name": "Brhodium", "coin_shortcut": "XRC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 70, "High": 200, "Low": 10, "Normal": 140}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://gitlab.com/bitcoinrh/BRhodiumNode", "hash_genesis_block": "baff5bfd9dc43fb672d003ec20fd21428f9282ca46bfa1730d73e1f2c75f5fdd", "key": "bitcoin:XRC", "maintainer": "baff5b ", "max_address_length": 34, "maxfee_kb": 2000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Bitcoin Rhodium", "segwit": false, "shortcut": "XRC", "signed_message_header": "BitCoin Rhodium Signed Message:\n", "slip44": 10291, "support": {"connect": false, "trezor1": "soon", "trezor2": "2.1.1", "webwallet": false}, "uri_prefix": "bitcoin-rhodium", "website": "https://www.bitcoinrh.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 3, "address_type_p2sh": 125, "bech32_prefix": "btx", "bip115": false, "bitcore": ["https://insight.bitcore.cc"], "blockbook": [], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Bitcore", "coin_name": "Bitcore", "coin_shortcut": "BTX", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Low": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/LIMXTEC/BitCore", "hash_genesis_block": "604148281e5c4b7f2487e5d03cd60d8e6f69411d613f6448034508cea52e9574", "key": "bitcoin:BTX", "maintainer": "limxdev ", "max_address_length": 34, "maxfee_kb": 2000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Bitcore", "segwit": true, "shortcut": "BTX", "signed_message_header": "BitCore Signed Message:\n", "slip44": 160, "support": {"connect": true, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "bitcore", "website": "https://bitcore.cc", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 102, "address_type_p2sh": 5, "bech32_prefix": "bsd", "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 200, "cashaddr_prefix": null, "coin_label": "Bitsend", "coin_name": "Bitsend", "coin_shortcut": "BSD", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 5460, "force_bip143": false, "fork_id": null, "github": "https://github.com/LIMXTEC/BitSend", "hash_genesis_block": "0000012e1b8843ac9ce8c18603658eaf8895f99d3f5e7e1b7b1686f35e3c087a", "key": "bitcoin:BSD", "maintainer": "limxdev ", "max_address_length": 34, "maxfee_kb": 1000000, "min_address_length": 27, "minfee_kb": 10000, "name": "Bitsend", "segwit": true, "shortcut": "BSD", "signed_message_header": "Bitsend Signed Message:\n", "slip44": 91, "support": {"connect": true, "trezor1": "1.7.2", "trezor2": "2.0.10", "webwallet": false}, "uri_prefix": "bitsend", "website": "https://bitsend.info", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 26, "address_type_p2sh": 5, "bech32_prefix": "bst", "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "BlockStamp", "coin_name": "BlockStamp", "coin_shortcut": "BST", "consensus_branch_id": null, "cooldown": 1000, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 70, "High": 200, "Low": 10, "Normal": 140}, "duplicate": true, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/BlockStamp/bst", "hash_genesis_block": "8000000049a2e26b0185be50b4b8ed58b707c8893762959f0b1673641cae1828", "key": "bitcoin:BST", "maintainer": "Krzysztof Kuchta ", "max_address_length": 34, "maxfee_kb": 2000000, "min_address_length": 27, "minfee_kb": 1000, "name": "BlockStamp", "segwit": true, "shortcut": "BST", "signed_message_header": "BST Signed Message:\n", "slip44": 254, "support": {"connect": false, "trezor1": "soon", "trezor2": "2.1.1", "webwallet": false}, "uri_prefix": "blockstamp", "website": "https://blockstamp.info", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 28, "address_type_p2sh": 35, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://blockbook.capricoin.org", "https://blockbook2.capricoin.org", "https://blockbook3.capricoin.org", "https://blockbook4.capricoin.org"], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Capricoin", "coin_name": "Capricoin", "coin_shortcut": "CPC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 7, "High": 20, "Low": 1, "Normal": 14}, "duplicate": true, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/Capricoinofficial/Capricoin", "hash_genesis_block": "00000d23fa0fc52c90893adb1181c9ddffb6c797a3e41864b9a23aa2f2981fe3", "key": "bitcoin:CPC", "maintainer": "Tibor Arpas ", "max_address_length": 34, "maxfee_kb": 2000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Capricoin", "segwit": false, "shortcut": "CPC", "signed_message_header": "Capricoin Signed Message:\n", "slip44": 289, "support": {"connect": true, "trezor1": false, "trezor2": "2.0.10", "webwallet": false}, "uri_prefix": "capricoin", "website": "https://capricoin.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 0, "address_type_p2sh": 28, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Crown", "coin_name": "Crown", "coin_shortcut": "CRW", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/Crowndev/crowncoin", "hash_genesis_block": "0000000085370d5e122f64f4ab19c68614ff3df78c8d13cb814fd7e69a1dc6da", "key": "bitcoin:CRW", "maintainer": "hypermist ", "max_address_length": 34, "maxfee_kb": 2000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Crown", "segwit": false, "shortcut": "CRW", "signed_message_header": "Crown Signed Message:\n", "slip44": 72, "support": {"connect": false, "trezor1": false, "trezor2": false, "webwallet": false}, "uri_prefix": "crown", "website": "https://crown.tech", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 76, "address_type_p2sh": 16, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://dash1.trezor.io", "https://dash2.trezor.io", "https://dash3.trezor.io", "https://dash4.trezor.io", "https://dash5.trezor.io"], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Dash", "coin_name": "Dash", "coin_shortcut": "DASH", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 5460, "force_bip143": false, "fork_id": null, "github": "https://github.com/dashpay/dash", "hash_genesis_block": "00000ffd590b1485b3caadc19b22e6379c733355108f107a430458cdf3407ab6", "key": "bitcoin:DASH", "maintainer": "Karel Bilek ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 1000, "name": "Dash", "segwit": false, "shortcut": "DASH", "signed_message_header": "DarkCoin Signed Message:\n", "slip44": 5, "support": {"connect": true, "trezor1": "1.5.2", "trezor2": "2.0.5", "webwallet": true}, "uri_prefix": "dash", "website": "https://www.dash.org", "xprv_magic": 50221816, "xpub_magic": 50221772, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 140, "address_type_p2sh": 19, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Dash Testnet", "coin_name": "Dash Testnet", "coin_shortcut": "tDASH", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 5460, "force_bip143": false, "fork_id": null, "github": "https://github.com/dashpay/dash", "hash_genesis_block": "00000bafbc94add76cb75e2ec92894837288a481e5c005f6563d91623bf8bc2c", "key": "bitcoin:tDASH", "maintainer": "Karel Bilek ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 10000, "name": "Dash Testnet", "segwit": false, "shortcut": "tDASH", "signed_message_header": "DarkCoin Signed Message:\n", "slip44": 1, "support": {"connect": true, "trezor1": "1.6.2", "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "dash", "website": "https://www.dash.org", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 1855, "address_type_p2sh": 1818, "bech32_prefix": null, "bip115": false, "bitcore": ["https://mainnet.decred.org"], "blockbook": [], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Decred", "coin_name": "Decred", "coin_shortcut": "DCR", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1_decred", "decred": true, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/decred/dcrd", "hash_genesis_block": "298e5cc3d985bfe7f81dc135f360abe089edd4396b86d2de66b0cef42b21d980", "key": "bitcoin:DCR", "maintainer": "Alex Yocom-Piatt ", "max_address_length": 35, "maxfee_kb": 1000000, "min_address_length": 35, "minfee_kb": 10000, "name": "Decred", "segwit": false, "shortcut": "DCR", "signed_message_header": "Decred Signed Message:\n", "slip44": 42, "support": {"connect": false, "trezor1": "1.6.2", "trezor2": "2.0.8", "webwallet": true}, "uri_prefix": "bitcoin", "website": "https://www.decred.org", "xprv_magic": 50177256, "xpub_magic": 50178342, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 3873, "address_type_p2sh": 3836, "bech32_prefix": null, "bip115": false, "bitcore": ["https://testnet.decred.org"], "blockbook": [], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Decred Testnet", "coin_name": "Decred Testnet", "coin_shortcut": "TDCR", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1_decred", "decred": true, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/decred/dcrd", "hash_genesis_block": "a649dce53918caf422e9c711c858837e08d626ecfcd198969b24f7b634a49bac", "key": "bitcoin:TDCR", "maintainer": "Saleem Rashid ", "max_address_length": 35, "maxfee_kb": 10000000, "min_address_length": 35, "minfee_kb": 1000, "name": "Decred Testnet", "segwit": false, "shortcut": "TDCR", "signed_message_header": "Decred Signed Message:\n", "slip44": 1, "support": {"connect": false, "trezor1": "1.6.2", "trezor2": "2.0.8", "webwallet": true}, "uri_prefix": "bitcoin", "website": "https://www.decred.org", "xprv_magic": 70615959, "xpub_magic": 70617041, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 30, "address_type_p2sh": 90, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 30, "cashaddr_prefix": null, "coin_label": "Denarius", "coin_name": "Denarius", "coin_shortcut": "DNR", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 54600, "force_bip143": false, "fork_id": null, "github": "https://github.com/carsenk/denarius", "hash_genesis_block": "00000d5dbbda01621cfc16bbc1f9bf3264d641a5dbf0de89fd0182c2c4828fcd", "key": "bitcoin:DNR", "maintainer": "carsenk ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 10000, "name": "Denarius", "segwit": false, "shortcut": "DNR", "signed_message_header": "Denarius Signed Message:\n", "slip44": 116, "support": {"connect": true, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "denarius", "website": "https://denarius.io", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 30, "address_type_p2sh": 63, "bech32_prefix": "dgb", "bip115": false, "bitcore": [], "blockbook": ["https://dgb1.trezor.io", "https://dgb2.trezor.io"], "blocktime_seconds": 15, "cashaddr_prefix": null, "coin_label": "DigiByte", "coin_name": "DigiByte", "coin_shortcut": "DGB", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 70, "High": 200, "Low": 10, "Normal": 140}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/digibyte/digibyte", "hash_genesis_block": "7497ea1b465eb39f1c8f507bc877078fe016d6fcb6dfad3a64c98dcc6e1e8496", "key": "bitcoin:DGB", "maintainer": "DigiByte ", "max_address_length": 34, "maxfee_kb": 500000, "min_address_length": 27, "minfee_kb": 1000, "name": "DigiByte", "segwit": true, "shortcut": "DGB", "signed_message_header": "DigiByte Signed Message:\n", "slip44": 20, "support": {"connect": true, "trezor1": "1.6.3", "trezor2": "2.0.7", "webwallet": true}, "uri_prefix": "digibyte", "website": "https://digibyte.io", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 30, "address_type_p2sh": 22, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://doge1.trezor.io", "https://doge2.trezor.io", "https://doge3.trezor.io", "https://doge4.trezor.io", "https://doge5.trezor.io"], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Dogecoin", "coin_name": "Dogecoin", "coin_shortcut": "DOGE", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 100000}, "dust_limit": 10000000, "force_bip143": false, "fork_id": null, "github": "https://github.com/dogecoin/dogecoin", "hash_genesis_block": "1a91e3dace36e2be3bf030a65679fe821aa1d6ef92e7c9902eb318182c355691", "key": "bitcoin:DOGE", "maintainer": "Karel Bilek ", "max_address_length": 34, "maxfee_kb": 1000000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Dogecoin", "segwit": false, "shortcut": "DOGE", "signed_message_header": "Dogecoin Signed Message:\n", "slip44": 3, "support": {"connect": true, "trezor1": "1.5.2", "trezor2": "2.0.5", "webwallet": true}, "uri_prefix": "dogecoin", "website": "https://dogecoin.com", "xprv_magic": 49988504, "xpub_magic": 49990397, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 95, "address_type_p2sh": 36, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 180, "cashaddr_prefix": null, "coin_label": "FairCoin", "coin_name": "FairCoin", "coin_shortcut": "FAIR", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 800000}, "dust_limit": 500000, "force_bip143": false, "fork_id": 0, "github": "https://github.com/faircoin/faircoin", "hash_genesis_block": "beed44fa5e96150d95d56ebd5d2625781825a9407a5215dd7eda723373a0a1d7", "key": "bitcoin:FAIR", "maintainer": "Santi Nore\u00f1a ", "max_address_length": 34, "maxfee_kb": 10000000, "min_address_length": 27, "minfee_kb": 1000, "name": "FairCoin", "segwit": false, "shortcut": "FAIR", "signed_message_header": "FairCoin Signed Message:\n", "slip44": 298, "support": {"connect": false, "trezor1": "soon", "trezor2": "2.1.1", "webwallet": false}, "uri_prefix": "faircoin", "website": "https://www.faircoin.world", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 14, "address_type_p2sh": 5, "bech32_prefix": "fc", "bip115": false, "bitcore": ["https://bitcore.feathercoin.com"], "blockbook": [], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Feathercoin", "coin_name": "Feathercoin", "coin_shortcut": "FTC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 1000}, "duplicate": true, "dust_limit": 54600, "force_bip143": false, "fork_id": null, "github": "https://github.com/FeatherCoin/Feathercoin", "hash_genesis_block": "12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2", "key": "bitcoin:FTC", "maintainer": "Lucas Betschart ", "max_address_length": 34, "maxfee_kb": 40000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Feathercoin", "segwit": true, "shortcut": "FTC", "signed_message_header": "Feathercoin Signed Message:\n", "slip44": 8, "support": {"connect": true, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "feathercoin", "website": "https://feathercoin.com", "xprv_magic": 76077806, "xpub_magic": 76069926, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 35, "address_type_p2sh": 94, "bech32_prefix": "flo", "bip115": false, "bitcore": ["https://livenet.flocha.in"], "blockbook": [], "blocktime_seconds": 40, "cashaddr_prefix": null, "coin_label": "Flo", "coin_name": "Florincoin", "coin_shortcut": "FLO", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 1000}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/floblockchain/flo", "hash_genesis_block": "09c7781c9df90708e278c35d38ea5c9041d7ecfcdd1c56ba67274b7cff3e1cea", "key": "bitcoin:FLO", "maintainer": "Robert English ", "max_address_length": 34, "maxfee_kb": 40000000, "min_address_length": 27, "minfee_kb": 100000, "name": "Flo", "segwit": true, "shortcut": "FLO", "signed_message_header": "Florincoin Signed Message:\n", "slip44": 216, "support": {"connect": true, "trezor1": "1.7.2", "trezor2": "2.0.11", "webwallet": false}, "uri_prefix": "florincoin", "website": "https://flo.cash", "xprv_magic": 15264107, "xpub_magic": 1526049, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 28471030}, {"address_type": 36, "address_type_p2sh": 16, "bech32_prefix": "fc", "bip115": false, "bitcore": [], "blockbook": ["https://explorer.fujicoin.org"], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Fujicoin", "coin_name": "Fujicoin", "coin_shortcut": "FJC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 20000, "High": 100000, "Low": 10000, "Normal": 50000}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/fujicoin/fujicoin", "hash_genesis_block": "adb6d9cfd74075e7f91608add4bd2a2ea636f70856183086842667a1597714a0", "key": "bitcoin:FJC", "maintainer": "motty ", "max_address_length": 34, "maxfee_kb": 1000000000, "min_address_length": 27, "minfee_kb": 10000000, "name": "Fujicoin", "segwit": true, "shortcut": "FJC", "signed_message_header": "FujiCoin Signed Message:\n", "slip44": 75, "support": {"connect": true, "trezor1": "1.6.1", "trezor2": "2.0.5", "webwallet": true}, "uri_prefix": "fujicoin", "website": "https://fujicoin.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 38, "address_type_p2sh": 10, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://blockbook.gincoin.io"], "blocktime_seconds": 120, "cashaddr_prefix": null, "coin_label": "GIN", "coin_name": "Gincoin", "coin_shortcut": "GIN", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 5460, "force_bip143": false, "fork_id": null, "github": "https://github.com/gincoin-dev/gincoin-core", "hash_genesis_block": "00000cd6bde619b2c3b23ad2e384328a450a37fa28731debf748c3b17f91f97d", "key": "bitcoin:GIN", "maintainer": "Dragos Badea ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 1000, "name": "GIN", "segwit": false, "shortcut": "GIN", "signed_message_header": "DarkCoin Signed Message:\n", "slip44": 2000, "support": {"connect": true, "trezor1": "1.7.2", "trezor2": "2.0.11", "webwallet": false}, "uri_prefix": "gincoin", "website": "https://gincoin.io", "xprv_magic": 50221816, "xpub_magic": 50221772, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 38, "address_type_p2sh": 62, "bech32_prefix": "game", "bip115": false, "bitcore": [], "blockbook": ["https://blockbook.gamecredits.network"], "blocktime_seconds": 90, "cashaddr_prefix": null, "coin_label": "GameCredits", "coin_name": "GameCredits", "coin_shortcut": "GAME", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 1000}, "dust_limit": 54600, "force_bip143": false, "fork_id": null, "github": "https://github.com/gamecredits-project/gamecredits", "hash_genesis_block": "91ec5f25ee9a0ffa1af7d4da4db9a552228dd2dc77cdb15b738be4e1f55f30ee", "key": "bitcoin:GAME", "maintainer": "Samad Sajanlal ", "max_address_length": 34, "maxfee_kb": 5000000, "min_address_length": 27, "minfee_kb": 100000, "name": "GameCredits", "segwit": true, "shortcut": "GAME", "signed_message_header": "GameCredits Signed Message:\n", "slip44": 101, "support": {"connect": true, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "gamecredits", "website": "https://gamecredits.org", "xprv_magic": 27108450, "xpub_magic": 27106558, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 28471030}, {"address_type": 36, "address_type_p2sh": 5, "bech32_prefix": "grs", "bip115": false, "bitcore": ["https://groestlsight.groestlcoin.org", "https://grsblocks.com"], "blockbook": ["https://blockbook.groestlcoin.org"], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Groestlcoin", "coin_name": "Groestlcoin", "coin_shortcut": "GRS", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1_groestl", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/Groestlcoin/groestlcoin", "hash_genesis_block": "00000ac5927c594d49cc0bdb81759d0da8297eb614683d3acb62f0703b639023", "key": "bitcoin:GRS", "maintainer": "Yura Pakhuchiy ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 1000, "name": "Groestlcoin", "segwit": true, "shortcut": "GRS", "signed_message_header": "GroestlCoin Signed Message:\n", "slip44": 17, "support": {"connect": false, "trezor1": "1.6.2", "trezor2": "2.0.8", "webwallet": true}, "uri_prefix": "groestlcoin", "website": "https://www.groestlcoin.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 111, "address_type_p2sh": 196, "bech32_prefix": "tgrs", "bip115": false, "bitcore": ["https://groestlsight-test.groestlcoin.org"], "blockbook": ["https://blockbook-test.groestlcoin.org"], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Groestlcoin Testnet", "coin_name": "Groestlcoin Testnet", "coin_shortcut": "tGRS", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1_groestl", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/Groestlcoin/groestlcoin", "hash_genesis_block": "000000ffbb50fc9898cdd36ec163e6ba23230164c0052a28876255b7dcf2cd36", "key": "bitcoin:tGRS", "maintainer": "Yura Pakhuchiy ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 1000, "name": "Groestlcoin Testnet", "segwit": true, "shortcut": "tGRS", "signed_message_header": "GroestlCoin Signed Message:\n", "slip44": 1, "support": {"connect": false, "trezor1": "1.6.2", "trezor2": "2.0.8", "webwallet": true}, "uri_prefix": "groestlcoin", "website": "https://www.groestlcoin.org", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": 73342198, "xpub_magic_segwit_p2sh": 71979618}, {"address_type": 8329, "address_type_p2sh": 8342, "bech32_prefix": null, "bip115": true, "bitcore": ["https://explorer.horizen.global"], "blockbook": [], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Horizen", "coin_name": "Horizen", "coin_shortcut": "ZEN", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/ZencashOfficial/zen", "hash_genesis_block": "0007104ccda289427919efc39dc9e4d499804b7bebc22df55f8b834301260602", "key": "bitcoin:ZEN", "maintainer": "Power_VANO ", "max_address_length": 95, "maxfee_kb": 2000000, "min_address_length": 35, "minfee_kb": 1000, "name": "Horizen", "segwit": false, "shortcut": "ZEN", "signed_message_header": "Zcash Signed Message:\n", "slip44": 121, "support": {"connect": true, "trezor1": false, "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "horizen", "website": "https://www.horizen.global", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 60, "address_type_p2sh": 85, "bech32_prefix": null, "bip115": false, "bitcore": ["https://api.kmd.dev"], "blockbook": [], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Komodo", "coin_name": "Komodo", "coin_shortcut": "KMD", "consensus_branch_id": {"1": 0, "2": 0, "3": 1537743641, "4": 1991772603}, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/komodoplatform/komodo", "hash_genesis_block": "027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71", "key": "bitcoin:KMD", "maintainer": "Kadan Stadelmann ", "max_address_length": 34, "maxfee_kb": 1000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Komodo", "segwit": false, "shortcut": "KMD", "signed_message_header": "Komodo Signed Message:\n", "slip44": 141, "support": {"connect": true, "trezor1": "1.8.0", "trezor2": "2.0.11", "webwallet": false}, "uri_prefix": "komodo", "website": "https://komodoplatform.com", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 6198, "address_type_p2sh": 6203, "bech32_prefix": null, "bip115": false, "bitcore": ["https://insight.kotocoin.info"], "blockbook": [], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Koto", "coin_name": "Koto", "coin_shortcut": "KOTO", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/KotoDevelopers/koto", "hash_genesis_block": "6d424c350729ae633275d51dc3496e16cd1b1d195c164da00f39c499a2e9959e", "key": "bitcoin:KOTO", "maintainer": "WO ", "max_address_length": 95, "maxfee_kb": 1000000, "min_address_length": 35, "minfee_kb": 1000, "name": "Koto", "segwit": false, "shortcut": "KOTO", "signed_message_header": "Koto Signed Message:\n", "slip44": 510, "support": {"connect": true, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": true}, "uri_prefix": "koto", "website": "https://ko-to.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 48, "address_type_p2sh": 50, "bech32_prefix": "ltc", "bip115": false, "bitcore": [], "blockbook": ["https://ltc1.trezor.io", "https://ltc2.trezor.io", "https://ltc3.trezor.io", "https://ltc4.trezor.io", "https://ltc5.trezor.io"], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Litecoin", "coin_name": "Litecoin", "coin_shortcut": "LTC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 1000}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/litecoin-project/litecoin", "hash_genesis_block": "12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2", "key": "bitcoin:LTC", "maintainer": "Pavol Rusnak ", "max_address_length": 34, "maxfee_kb": 40000000, "min_address_length": 27, "minfee_kb": 100000, "name": "Litecoin", "segwit": true, "shortcut": "LTC", "signed_message_header": "Litecoin Signed Message:\n", "slip44": 2, "support": {"connect": true, "trezor1": "1.5.2", "trezor2": "2.0.5", "webwallet": true}, "uri_prefix": "litecoin", "website": "https://litecoin.org", "xprv_magic": 27106558, "xpub_magic": 27108450, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 28471030}, {"address_type": 111, "address_type_p2sh": 58, "bech32_prefix": "tltc", "bip115": false, "bitcore": ["https://testnet.litecore.io"], "blockbook": [], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Litecoin Testnet", "coin_name": "Litecoin Testnet", "coin_shortcut": "tLTC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 54600, "force_bip143": false, "fork_id": null, "github": "https://github.com/litecoin-project/litecoin", "hash_genesis_block": "4966625a4b2851d9fdee139e56211a0d88575f59ed816ff5e6a63deb4e3e29a0", "key": "bitcoin:tLTC", "maintainer": "Pavol Rusnak ", "max_address_length": 34, "maxfee_kb": 40000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Litecoin Testnet", "segwit": true, "shortcut": "tLTC", "signed_message_header": "Litecoin Signed Message:\n", "slip44": 1, "support": {"connect": true, "trezor1": "1.6.2", "trezor2": "2.0.7", "webwallet": true}, "uri_prefix": "litecoin", "website": "https://litecoin.org", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": 73342198, "xpub_magic_segwit_p2sh": 71979618}, {"address_type": 50, "address_type_p2sh": 5, "bech32_prefix": "mec", "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Megacoin", "coin_name": "Megacoin", "coin_shortcut": "MEC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Low": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/LIMXTEC/Megacoin", "hash_genesis_block": "7520788e2d99eec7cf6cf7315577e1268e177fff94cb0a7caf6a458ceeea9ac2", "key": "bitcoin:MEC", "maintainer": "limxdev ", "max_address_length": 34, "maxfee_kb": 1000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Megacoin", "segwit": true, "shortcut": "MEC", "signed_message_header": "MegaCoin Signed Message:\n", "slip44": 217, "support": {"connect": true, "trezor1": "1.7.2", "trezor2": "2.0.10", "webwallet": false}, "uri_prefix": "megacoin", "website": "https://www.megacoin.eu", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 50, "address_type_p2sh": 55, "bech32_prefix": "mona", "bip115": false, "bitcore": ["https://mona.chainsight.info", "https://insight.electrum-mona.org"], "blockbook": ["https://blockbook.electrum-mona.org"], "blocktime_seconds": 90, "cashaddr_prefix": null, "coin_label": "Monacoin", "coin_name": "Monacoin", "coin_shortcut": "MONA", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 1000}, "dust_limit": 54600, "force_bip143": false, "fork_id": null, "github": "https://github.com/monacoinproject/monacoin", "hash_genesis_block": "ff9f1c0116d19de7c9963845e129f9ed1bfc0b376eb54fd7afa42e0d418c8bb6", "key": "bitcoin:MONA", "maintainer": "cryptcoin-junkey ", "max_address_length": 34, "maxfee_kb": 5000000, "min_address_length": 27, "minfee_kb": 100000, "name": "Monacoin", "segwit": true, "shortcut": "MONA", "signed_message_header": "Monacoin Signed Message:\n", "slip44": 22, "support": {"connect": true, "trezor1": "1.6.0", "trezor2": "2.0.5", "webwallet": true}, "uri_prefix": "monacoin", "website": "https://monacoin.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 16, "address_type_p2sh": 76, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://blockbook.monetaryunit.org"], "blocktime_seconds": 40, "cashaddr_prefix": null, "coin_label": "MonetaryUnit", "coin_name": "MonetaryUnit", "coin_shortcut": "MUE", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 5460, "force_bip143": false, "fork_id": null, "github": "https://github.com/muecoin/MUE", "hash_genesis_block": "0b58ed450b3819ca54ab0054c4d220ca4f887d21c9e55d2a333173adf76d987f", "key": "bitcoin:MUE", "maintainer": "Sotiris Blad ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 1000, "name": "MonetaryUnit", "segwit": false, "shortcut": "MUE", "signed_message_header": "MonetaryUnit Signed Message:\n", "slip44": 31, "support": {"connect": true, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "monetaryunit", "website": "https://www.monetaryunit.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 50, "address_type_p2sh": 9, "bech32_prefix": "my", "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Myriad", "coin_name": "Myriad", "coin_shortcut": "XMY", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 70, "High": 200, "Low": 10, "Normal": 140}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/myriadteam/myriadcoin", "hash_genesis_block": "00000ffde4c020b5938441a0ea3d314bf619eff0b38f32f78f7583cffa1ea485", "key": "bitcoin:XMY", "maintainer": "Adam Hickerson ", "max_address_length": 34, "maxfee_kb": 2000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Myriad", "segwit": true, "shortcut": "XMY", "signed_message_header": "Myriadcoin Signed Message:\n", "slip44": 90, "support": {"connect": true, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "myriadcoin", "website": "https://www.myriadcoin.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 38, "address_type_p2sh": 53, "bech32_prefix": "nix", "bip115": false, "bitcore": ["https://blockchain.nixplatform.io"], "blockbook": [], "blocktime_seconds": 120, "cashaddr_prefix": null, "coin_label": "NIX", "coin_name": "NIX", "coin_shortcut": "NIX", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 1000}, "dust_limit": 54600, "force_bip143": false, "fork_id": null, "github": "https://github.com/nixplatform/nixcore", "hash_genesis_block": "dd28ad86def767c3cfc34267a950d871fc7462bc57ea4a929fc3596d9b598e41", "key": "bitcoin:NIX", "maintainer": "mattt21 ", "max_address_length": 34, "maxfee_kb": 40000000, "min_address_length": 27, "minfee_kb": 0, "name": "NIX", "segwit": true, "shortcut": "NIX", "signed_message_header": "NIX Signed Message:\n", "slip44": 400, "support": {"connect": true, "trezor1": "1.7.2", "trezor2": "2.0.11", "webwallet": false}, "uri_prefix": "nix", "website": "https://nixplatform.io", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 52, "address_type_p2sh": 5, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://nmc1.trezor.io", "https://nmc2.trezor.io"], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Namecoin", "coin_name": "Namecoin", "coin_shortcut": "NMC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 2940, "force_bip143": false, "fork_id": null, "github": "https://github.com/namecoin/namecoin-core", "hash_genesis_block": "000000000062b72c5e2ceb45fbc8587e807c155b0da735e6483dfba2f0a9c770", "key": "bitcoin:NMC", "maintainer": "Pavol Rusnak ", "max_address_length": 34, "maxfee_kb": 10000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Namecoin", "segwit": false, "shortcut": "NMC", "signed_message_header": "Namecoin Signed Message:\n", "slip44": 7, "support": {"connect": true, "trezor1": "1.5.2", "trezor2": "2.0.5", "webwallet": true}, "uri_prefix": "namecoin", "website": "https://namecoin.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 30, "address_type_p2sh": 13, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://blockbook.pivx.link"], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "PIVX", "coin_name": "PIVX", "coin_shortcut": "PIVX", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/PIVX-Project/PIVX", "hash_genesis_block": "0000041e482b9b9691d98eefb48473405c0b8ec31b76df3797c74a78680ef818", "key": "bitcoin:PIVX", "maintainer": "Random Zebra ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 100, "name": "PIVX", "segwit": false, "shortcut": "PIVX", "signed_message_header": "DarkNet Signed Message:\n", "slip44": 119, "support": {"connect": true, "trezor1": "1.8.0", "trezor2": "2.0.11", "webwallet": false}, "uri_prefix": "pivx", "website": "https://pivx.org", "xprv_magic": 35729707, "xpub_magic": 36513075, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 139, "address_type_p2sh": 19, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://blockbook-testnet.pivx.link"], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "PIVX Testnet", "coin_name": "PIVX Testnet", "coin_shortcut": "tPIVX", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 54600, "force_bip143": false, "fork_id": null, "github": "https://github.com/PIVX-Project/PIVX", "hash_genesis_block": "0000041e482b9b9691d98eefb48473405c0b8ec31b76df3797c74a78680ef818", "key": "bitcoin:tPIVX", "maintainer": "Random Zebra ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 100, "name": "PIVX Testnet", "segwit": false, "shortcut": "tPIVX", "signed_message_header": "DarkNet Signed Message:\n", "slip44": 1, "support": {"connect": true, "trezor1": "1.8.0", "trezor2": "2.0.11", "webwallet": false}, "uri_prefix": "pivx", "website": "https://pivx.org", "xprv_magic": 981489719, "xpub_magic": 981492128, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 47, "address_type_p2sh": 22, "bech32_prefix": null, "bip115": false, "bitcore": ["https://live.pesetacoin.info"], "blockbook": [], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Pesetacoin", "coin_name": "Pesetacoin", "coin_shortcut": "PTC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "duplicate": true, "dust_limit": 10000000, "force_bip143": false, "fork_id": null, "github": "https://github.com/FundacionPesetacoin/PesetacoinCore", "hash_genesis_block": "edfe5830b53251bfff733600b1cd5c192e761c011b055f07924634818c906438", "key": "bitcoin:PTC", "maintainer": "Rw ", "max_address_length": 34, "maxfee_kb": 1000000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Pesetacoin", "segwit": false, "shortcut": "PTC", "signed_message_header": "Pesetacoin Signed Message:\n", "slip44": 109, "support": {"connect": true, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "pesetacoin", "website": "https://pesetacoin.info", "xprv_magic": 76079604, "xpub_magic": 76071982, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 55, "address_type_p2sh": 56, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://blockbook.polispay.org"], "blocktime_seconds": 120, "cashaddr_prefix": null, "coin_label": "Polis", "coin_name": "Polis", "coin_shortcut": "POLIS", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 5460, "force_bip143": false, "fork_id": null, "github": "https://github.com/polispay/polis", "hash_genesis_block": "000009701eb781a8113b1af1d814e2f060f6408a2c990db291bc5108a1345c1e", "key": "bitcoin:POLIS", "maintainer": "Cronos ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 1000, "name": "Polis", "segwit": false, "shortcut": "POLIS", "signed_message_header": "Polis Signed Message:\n", "slip44": 1997, "support": {"connect": false, "trezor1": "soon", "trezor2": "2.1.1", "webwallet": false}, "uri_prefix": "polis", "website": "https://www.polispay.org", "xprv_magic": 65165637, "xpub_magic": 65166718, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 23, "address_type_p2sh": 83, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Primecoin", "coin_name": "Primecoin", "coin_shortcut": "XPM", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/primecoin/primecoin", "hash_genesis_block": "963d17ba4dc753138078a2f56afb3af9674e2546822badff26837db9a0152106", "key": "bitcoin:XPM", "maintainer": "James Skrowvedeht ", "max_address_length": 35, "maxfee_kb": 1000000, "min_address_length": 26, "minfee_kb": 1000, "name": "Primecoin", "segwit": false, "shortcut": "XPM", "signed_message_header": "Primecoin Signed Message:\n", "slip44": 24, "support": {"connect": true, "trezor1": "1.8.0", "trezor2": "2.0.11", "webwallet": false}, "uri_prefix": "primecoin", "website": "https://primecoin.io", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 58, "address_type_p2sh": 50, "bech32_prefix": "qc", "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 128, "cashaddr_prefix": null, "coin_label": "Qtum", "coin_name": "Qtum", "coin_shortcut": "QTUM", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 500, "High": 2000, "Low": 410, "Normal": 600}, "duplicate": true, "dust_limit": 218400, "force_bip143": false, "fork_id": null, "github": "https://github.com/qtumproject/qtum", "hash_genesis_block": "000075aef83cf2853580f8ae8ce6f8c3096cfa21d98334d6e3f95e5582ed986c", "key": "bitcoin:QTUM", "maintainer": "CodeFace ", "max_address_length": 34, "maxfee_kb": 40000000, "min_address_length": 27, "minfee_kb": 400000, "name": "Qtum", "segwit": true, "shortcut": "QTUM", "signed_message_header": "Qtum Signed Message:\n", "slip44": 2301, "support": {"connect": false, "trezor1": "1.8.1", "trezor2": "2.1.1", "webwallet": false}, "uri_prefix": "qtum", "website": "https://qtum.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 120, "address_type_p2sh": 110, "bech32_prefix": "tq", "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 128, "cashaddr_prefix": null, "coin_label": "Qtum Testnet", "coin_name": "Qtum Testnet", "coin_shortcut": "tQTUM", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 500, "High": 2000, "Low": 410, "Normal": 600}, "dust_limit": 218400, "force_bip143": false, "fork_id": null, "github": "https://github.com/qtumproject/qtum", "hash_genesis_block": "0000e803ee215c0684ca0d2f9220594d3f828617972aad66feb2ba51f5e14222", "key": "bitcoin:tQTUM", "maintainer": "CodeFace ", "max_address_length": 34, "maxfee_kb": 40000000, "min_address_length": 27, "minfee_kb": 400000, "name": "Qtum Testnet", "segwit": true, "shortcut": "tQTUM", "signed_message_header": "Qtum Signed Message:\n", "slip44": 1, "support": {"connect": false, "trezor1": "1.8.1", "trezor2": "2.1.1", "webwallet": false}, "uri_prefix": "qtum", "website": "https://qtum.org", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": 73342198, "xpub_magic_segwit_p2sh": 71979618}, {"address_type": 60, "address_type_p2sh": 122, "bech32_prefix": null, "bip115": false, "bitcore": ["https://ravencoin.network"], "blockbook": ["https://blockbook.ravencoin.org"], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Ravencoin", "coin_name": "Ravencoin", "coin_shortcut": "RVN", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Low": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/RavenProject/Ravencoin", "hash_genesis_block": "0000006b444bc2f2ffe627be9d9e7e7a0730000870ef6eb6da46c8eae389df90", "key": "bitcoin:RVN", "maintainer": "Scotty ", "max_address_length": 34, "maxfee_kb": 2000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Ravencoin", "segwit": false, "shortcut": "RVN", "signed_message_header": "Raven Signed Message:\n", "slip44": 175, "support": {"connect": true, "trezor1": "1.7.2", "trezor2": "2.0.10", "webwallet": true}, "uri_prefix": "raven", "website": "https://ravencoin.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 111, "address_type_p2sh": 196, "bech32_prefix": "bcrt", "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Regtest", "coin_name": "Regtest", "coin_shortcut": "REGTEST", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/bitcoin/bitcoin", "hash_genesis_block": "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206", "key": "bitcoin:REGTEST", "maintainer": "Thomas Kerin ", "max_address_length": 34, "maxfee_kb": 10000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Regtest", "segwit": true, "shortcut": "REGTEST", "signed_message_header": "Bitcoin Signed Message:\n", "slip44": 1, "support": {"connect": false, "trezor1": "1.8.2", "trezor2": "2.1.1", "webwallet": false}, "uri_prefix": "bitcoin", "website": "https://bitcoin.org", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": 73342198, "xpub_magic_segwit_p2sh": 71979618}, {"address_type": 25, "address_type_p2sh": 105, "bech32_prefix": null, "bip115": false, "bitcore": ["https://insight.ritocoin.org"], "blockbook": ["https://blockbook.ritocoin.org"], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Ritocoin", "coin_name": "Ritocoin", "coin_shortcut": "RITO", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Low": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/RitoProject", "hash_genesis_block": "00000075e344bdf1c0e433f453764b1830a7aa19b2a5213e707502a22b779c1b", "key": "bitcoin:RITO", "maintainer": "Scotty ", "max_address_length": 34, "maxfee_kb": 2000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Ritocoin", "segwit": false, "shortcut": "RITO", "signed_message_header": "Rito Signed Message:\n", "slip44": 19169, "support": {"connect": false, "trezor1": "1.8.2", "trezor2": "2.1.1", "webwallet": false}, "uri_prefix": "rito", "website": "https://ritocoin.org", "xprv_magic": 87326380, "xpub_magic": 87353290, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 63, "address_type_p2sh": 18, "bech32_prefix": null, "bip115": false, "bitcore": ["https://insight.smartcash.cc"], "blockbook": [], "blocktime_seconds": 55, "cashaddr_prefix": null, "coin_label": "SmartCash", "coin_name": "SmartCash", "coin_shortcut": "SMART", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1_smart", "decred": false, "default_fee_b": {"Economy": 10, "High": 200, "Low": 1, "Normal": 100}, "duplicate": true, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/SmartCash/Core-Smart", "hash_genesis_block": "000007acc6970b812948d14ea5a0a13db0fdd07d5047c7e69101fa8b361e05a4", "key": "bitcoin:SMART", "maintainer": "Leandro Reinaux ", "max_address_length": 34, "maxfee_kb": 1000000, "min_address_length": 27, "minfee_kb": 0, "name": "SmartCash", "segwit": false, "shortcut": "SMART", "signed_message_header": "SmartCash Signed Message:\n", "slip44": 224, "support": {"connect": false, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "smart", "website": "https://smartcash.cc", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 65, "address_type_p2sh": 21, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 55, "cashaddr_prefix": null, "coin_label": "SmartCash Testnet", "coin_name": "SmartCash Testnet", "coin_shortcut": "tSMART", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1_smart", "decred": false, "default_fee_b": {"Economy": 10, "High": 200, "Low": 1, "Normal": 100}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/SmartCash/Core-Smart", "hash_genesis_block": "0000027235b5679bcd28c90d03d4bf1a9ba4c07c4efcc1c87d6c68cce25e6e5d", "key": "bitcoin:tSMART", "maintainer": "Leandro Reinaux ", "max_address_length": 35, "maxfee_kb": 1000000, "min_address_length": 27, "minfee_kb": 0, "name": "SmartCash Testnet", "segwit": false, "shortcut": "tSMART", "signed_message_header": "SmartCash Signed Message:\n", "slip44": 224, "support": {"connect": false, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "testsmart", "website": "https://smartcash.cc", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 76, "address_type_p2sh": 16, "bech32_prefix": "xc", "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Stakenet", "coin_name": "Stakenet", "coin_shortcut": "XSN", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 70, "High": 200, "Low": 10, "Normal": 140}, "dust_limit": 1000, "force_bip143": false, "fork_id": null, "github": "https://github.com/X9Developers/XSN", "hash_genesis_block": "00000c822abdbb23e28f79a49d29b41429737c6c7e15df40d1b1f1b35907ae34", "key": "bitcoin:XSN", "maintainer": "Alexis Hernandez ", "max_address_length": 47, "maxfee_kb": 2000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Stakenet", "segwit": true, "shortcut": "XSN", "signed_message_header": "DarkCoin Signed Message:\n", "slip44": 199, "support": {"connect": true, "trezor1": "1.8.0", "trezor2": "2.0.11", "webwallet": false}, "uri_prefix": "stakenet", "website": "https://stakenet.io", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 0, "address_type_p2sh": 5, "bech32_prefix": null, "bip115": false, "bitcore": ["https://insight.terracoin.io"], "blockbook": [], "blocktime_seconds": 120, "cashaddr_prefix": null, "coin_label": "Terracoin", "coin_name": "Terracoin", "coin_shortcut": "TRC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "duplicate": true, "dust_limit": 5460, "force_bip143": false, "fork_id": null, "github": "https://github.com/terracoin/terracoin", "hash_genesis_block": "00000000804bbc6a621a9dbb564ce469f492e1ccf2d70f8a6b241e26a277afa2", "key": "bitcoin:TRC", "maintainer": "The Terracoin Foundation ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 10000, "name": "Terracoin", "segwit": false, "shortcut": "TRC", "signed_message_header": "DarkCoin Signed Message:\n", "slip44": 83, "support": {"connect": false, "trezor1": false, "trezor2": false, "webwallet": false}, "uri_prefix": "terracoin", "website": "https://terracoin.io", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 70, "address_type_p2sh": 50, "bech32_prefix": "vips", "bip115": false, "bitcore": ["https://insight.vipstarco.in"], "blockbook": ["https://vips.blockbook.japanesecoin-pool.work"], "blocktime_seconds": 120, "cashaddr_prefix": null, "coin_label": "VIPSTARCOIN", "coin_name": "VIPSTARCOIN", "coin_shortcut": "VIPS", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 500, "High": 2000, "Low": 410, "Normal": 600}, "dust_limit": 218400, "force_bip143": false, "fork_id": null, "github": "https://github.com/VIPSTARCOIN/VIPSTARCOIN", "hash_genesis_block": "0000d068e1d30f79fb64446137106be9c6ee69a6a722295c131506b1ee09b77c", "key": "bitcoin:VIPS", "maintainer": "y-chan ", "max_address_length": 36, "maxfee_kb": 40000000, "min_address_length": 27, "minfee_kb": 400000, "name": "VIPSTARCOIN", "segwit": true, "shortcut": "VIPS", "signed_message_header": "VIPSTARCOIN Signed Message:\n", "slip44": 1919, "support": {"connect": false, "trezor1": "1.8.2", "trezor2": "2.1.1", "webwallet": false}, "uri_prefix": "vipstarcoin", "website": "https://vipstarcoin.jp", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 71, "address_type_p2sh": 5, "bech32_prefix": "vtc", "bip115": false, "bitcore": [], "blockbook": ["https://vtc1.trezor.io", "https://vtc2.trezor.io", "https://vtc3.trezor.io", "https://vtc4.trezor.io", "https://vtc5.trezor.io"], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Vertcoin", "coin_name": "Vertcoin", "coin_shortcut": "VTC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 1000}, "dust_limit": 54600, "force_bip143": false, "fork_id": null, "github": "https://github.com/vertcoin-project/vertcoin-core", "hash_genesis_block": "4d96a915f49d40b1e5c2844d1ee2dccb90013a990ccea12c492d22110489f0c4", "key": "bitcoin:VTC", "maintainer": "Jochen Hoenicke ", "max_address_length": 34, "maxfee_kb": 40000000, "min_address_length": 27, "minfee_kb": 100000, "name": "Vertcoin", "segwit": true, "shortcut": "VTC", "signed_message_header": "Vertcoin Signed Message:\n", "slip44": 28, "support": {"connect": true, "trezor1": "1.6.1", "trezor2": "2.0.5", "webwallet": true}, "uri_prefix": "vertcoin", "website": "https://vertcoin.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 71, "address_type_p2sh": 33, "bech32_prefix": "via", "bip115": false, "bitcore": ["https://explorer.viacoin.org"], "blockbook": [], "blocktime_seconds": 24, "cashaddr_prefix": null, "coin_label": "Viacoin", "coin_name": "Viacoin", "coin_shortcut": "VIA", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 7000, "High": 20000, "Low": 1000, "Normal": 14000}, "dust_limit": 54600, "force_bip143": false, "fork_id": null, "github": "https://github.com/viacoin", "hash_genesis_block": "4e9b54001f9976049830128ec0331515eaabe35a70970d79971da1539a400ba1", "key": "bitcoin:VIA", "maintainer": "romanornr ", "max_address_length": 34, "maxfee_kb": 40000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Viacoin", "segwit": true, "shortcut": "VIA", "signed_message_header": "Viacoin Signed Message:\n", "slip44": 14, "support": {"connect": true, "trezor1": "1.6.2", "trezor2": "2.0.7", "webwallet": true}, "uri_prefix": "viacoin", "website": "https://viacoin.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 7352, "address_type_p2sh": 7357, "bech32_prefix": null, "bip115": false, "bitcore": ["https://explorer.zcl.zeltrez.io"], "blockbook": [], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "ZClassic", "coin_name": "ZClassic", "coin_shortcut": "ZCL", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/ZclassicCommunity", "hash_genesis_block": "0007104ccda289427919efc39dc9e4d499804b7bebc22df55f8b834301260602", "key": "bitcoin:ZCL", "maintainer": "James Skrowvedeht ", "max_address_length": 95, "maxfee_kb": 1000000, "min_address_length": 35, "minfee_kb": 1000, "name": "ZClassic", "segwit": false, "shortcut": "ZCL", "signed_message_header": "Zcash Signed Message:\n", "slip44": 147, "support": {"connect": true, "trezor1": "1.8.0", "trezor2": "2.0.11", "webwallet": false}, "uri_prefix": "zclassic", "website": "https://zclassic.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 7352, "address_type_p2sh": 7357, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://zec1.trezor.io", "https://zec2.trezor.io", "https://zec3.trezor.io", "https://zec4.trezor.io", "https://zec5.trezor.io"], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Zcash", "coin_name": "Zcash", "coin_shortcut": "ZEC", "consensus_branch_id": {"1": 0, "2": 0, "3": 1537743641, "4": 1991772603}, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/zcash/zcash", "hash_genesis_block": "00040fe8ec8471911baa1db1266ea15dd06b4a8a5c453883c000b031973dce08", "key": "bitcoin:ZEC", "maintainer": "Pavol Rusnak ", "max_address_length": 95, "maxfee_kb": 1000000, "min_address_length": 35, "minfee_kb": 1000, "name": "Zcash", "segwit": false, "shortcut": "ZEC", "signed_message_header": "Zcash Signed Message:\n", "slip44": 133, "support": {"connect": true, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": true}, "uri_prefix": "zcash", "website": "https://z.cash", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 7461, "address_type_p2sh": 7354, "bech32_prefix": null, "bip115": false, "bitcore": ["https://explorer.testnet.z.cash"], "blockbook": [], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Zcash Testnet", "coin_name": "Zcash Testnet", "coin_shortcut": "TAZ", "consensus_branch_id": {"1": 0, "2": 0, "3": 1537743641, "4": 1991772603}, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/zcash/zcash", "hash_genesis_block": "05a60a92d99d85997cce3b87616c089f6124d7342af37106edc76126334a2c38", "key": "bitcoin:TAZ", "maintainer": "Pavol Rusnak ", "max_address_length": 95, "maxfee_kb": 10000000, "min_address_length": 35, "minfee_kb": 1000, "name": "Zcash Testnet", "segwit": false, "shortcut": "TAZ", "signed_message_header": "Zcash Signed Message:\n", "slip44": 1, "support": {"connect": true, "trezor1": "1.6.2", "trezor2": "2.0.7", "webwallet": true}, "uri_prefix": "zcash", "website": "https://z.cash", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 82, "address_type_p2sh": 7, "bech32_prefix": null, "bip115": false, "bitcore": ["https://insight.zcoin.io"], "blockbook": [], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Zcoin", "coin_name": "Zcoin", "coin_shortcut": "XZC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 10, "High": 200, "Low": 1, "Normal": 100}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/zcoinofficial/zcoin", "hash_genesis_block": "4381deb85b1b2c9843c222944b616d997516dcbd6a964e1eaf0def0830695233", "key": "bitcoin:XZC", "maintainer": "Yura Pakhuchiy ", "max_address_length": 34, "maxfee_kb": 1000000, "min_address_length": 27, "minfee_kb": 0, "name": "Zcoin", "segwit": false, "shortcut": "XZC", "signed_message_header": "Zcoin Signed Message:\n", "slip44": 136, "support": {"connect": true, "trezor1": "1.6.2", "trezor2": "2.0.7", "webwallet": true}, "uri_prefix": "zcoin", "website": "https://zcoin.io", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 65, "address_type_p2sh": 178, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Zcoin Testnet", "coin_name": "Zcoin Testnet", "coin_shortcut": "tXZC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 10, "High": 200, "Low": 1, "Normal": 100}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/zcoinofficial/zcoin", "hash_genesis_block": "7ac038c193c2158c428c59f9ae0c02a07115141c6e9dc244ae96132e99b4e642", "key": "bitcoin:tXZC", "maintainer": "Yura Pakhuchiy ", "max_address_length": 35, "maxfee_kb": 1000000, "min_address_length": 27, "minfee_kb": 0, "name": "Zcoin Testnet", "segwit": false, "shortcut": "tXZC", "signed_message_header": "Zcoin Signed Message:\n", "slip44": 1, "support": {"connect": true, "trezor1": "1.6.2", "trezor2": "2.0.7", "webwallet": false}, "uri_prefix": "testzcoin", "website": "https://zcoin.io", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}] +[{"address_type": 0, "address_type_p2sh": 5, "bech32_prefix": "bc", "bip115": false, "bitcore": [], "blockbook": ["https://btc1.trezor.io", "https://btc2.trezor.io", "https://btc3.trezor.io", "https://btc4.trezor.io", "https://btc5.trezor.io"], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Bitcoin", "coin_name": "Bitcoin", "coin_shortcut": "BTC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 70, "High": 200, "Low": 10, "Normal": 140}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/bitcoin/bitcoin", "hash_genesis_block": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", "key": "bitcoin:BTC", "maintainer": "Pavol Rusnak ", "max_address_length": 34, "maxfee_kb": 2000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Bitcoin", "segwit": true, "shortcut": "BTC", "signed_message_header": "Bitcoin Signed Message:\n", "slip44": 0, "support": {"connect": true, "trezor1": "1.5.2", "trezor2": "2.0.5", "webwallet": true}, "uri_prefix": "bitcoin", "website": "https://bitcoin.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 111, "address_type_p2sh": 196, "bech32_prefix": "tb", "bip115": false, "bitcore": [], "blockbook": ["https://tbtc1.trezor.io", "https://tbtc2.trezor.io"], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Testnet", "coin_name": "Testnet", "coin_shortcut": "TEST", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/bitcoin/bitcoin", "hash_genesis_block": "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943", "key": "bitcoin:TEST", "maintainer": "Pavol Rusnak ", "max_address_length": 34, "maxfee_kb": 10000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Testnet", "segwit": true, "shortcut": "TEST", "signed_message_header": "Bitcoin Signed Message:\n", "slip44": 1, "support": {"connect": true, "trezor1": "1.5.2", "trezor2": "2.0.5", "webwallet": true}, "uri_prefix": "bitcoin", "website": "https://bitcoin.org", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": 73342198, "xpub_magic_segwit_p2sh": 71979618}, {"address_type": 53, "address_type_p2sh": 55, "bech32_prefix": "acm", "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Actinium", "coin_name": "Actinium", "coin_shortcut": "ACM", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 1000}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/Actinium-project/Actinium", "hash_genesis_block": "28d77872e23714562f49a1be792c276623c1bbe3fdcf21b6035cfde78b00b824", "key": "bitcoin:ACM", "maintainer": "Harris Brakmic ", "max_address_length": 34, "maxfee_kb": 40000000, "min_address_length": 27, "minfee_kb": 100000, "name": "Actinium", "segwit": true, "shortcut": "ACM", "signed_message_header": "Actinium Signed Message:\n", "slip44": 228, "support": {"connect": true, "trezor1": "1.7.2", "trezor2": "2.0.10", "webwallet": true}, "uri_prefix": "actinium", "website": "https://actinium.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 55, "address_type_p2sh": 16, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Axe", "coin_name": "Axe", "coin_shortcut": "AXE", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 5460, "force_bip143": false, "fork_id": null, "github": "https://github.com/axerunners/axe", "hash_genesis_block": "00000c33631ca6f2f61368991ce2dc03306b5bb50bf7cede5cfbba6db38e52e6", "key": "bitcoin:AXE", "maintainer": "Kirill Orlov ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 1000, "name": "Axe", "segwit": false, "shortcut": "AXE", "signed_message_header": "DarkCoin Signed Message:\n", "slip44": 4242, "support": {"connect": true, "trezor1": "1.7.3", "trezor2": "2.0.11", "webwallet": false}, "uri_prefix": "axe", "website": "https://axerunners.com", "xprv_magic": 50221816, "xpub_magic": 50221772, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 25, "address_type_p2sh": 85, "bech32_prefix": "bm", "bip115": false, "bitcore": [], "blockbook": ["https://bellcoin-blockbook.ilmango.work", "https://bell.blockbook.ovh"], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Bellcoin", "coin_name": "Bellcoin", "coin_shortcut": "BELL", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 20}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/bellcoin-org/bellcoin", "hash_genesis_block": "000008f3b6bd10c2d03b06674a006b8d9731f6cb58179ef1eee008cee2209603", "key": "bitcoin:BELL", "maintainer": "ilmango-doge ", "max_address_length": 34, "maxfee_kb": 1000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Bellcoin", "segwit": true, "shortcut": "BELL", "signed_message_header": "Bellcoin Signed Message:\n", "slip44": 25252, "support": {"connect": false, "trezor1": "1.8.2", "trezor2": "2.1.1", "webwallet": false}, "uri_prefix": "bellcoin", "website": "https://bellcoin.web4u.jp", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 230, "address_type_p2sh": 235, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "BitCash", "coin_name": "BitCash", "coin_shortcut": "BITC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 70, "High": 200, "Low": 10, "Normal": 140}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/WillyTheCat/BitCash", "hash_genesis_block": "7d57d87ff3c15a521530af60edee1887fba9c193eb518face926785c4cd8f4f1", "key": "bitcoin:BITC", "maintainer": "Christian Kassler ", "max_address_length": 53, "maxfee_kb": 30000000, "min_address_length": 52, "minfee_kb": 1000, "name": "BitCash", "segwit": false, "shortcut": "BITC", "signed_message_header": "Bitcash Signed Message:\n", "slip44": 230, "support": {"connect": true, "trezor1": "1.7.2", "trezor2": "2.0.10", "webwallet": false}, "uri_prefix": "bitcash", "website": "https://www.choosebitcash.com", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 81, "address_type_p2sh": 5, "bech32_prefix": "bz", "bip115": false, "bitcore": ["https://insight.bitzeny.jp", "https://zeny.insight.monaco-ex.org"], "blockbook": ["https://zny.blockbook.ovh"], "blocktime_seconds": 90, "cashaddr_prefix": null, "coin_label": "BitZeny", "coin_name": "BitZeny", "coin_shortcut": "ZNY", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 20}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/BitzenyCoreDevelopers/bitzeny", "hash_genesis_block": "000009f7e55e9e3b4781e22bd87a7cfa4acada9e4340d43ca738bf4e9fb8f5ce", "key": "bitcoin:ZNY", "maintainer": "y-chan ", "max_address_length": 34, "maxfee_kb": 1000000, "min_address_length": 27, "minfee_kb": 1000, "name": "BitZeny", "segwit": true, "shortcut": "ZNY", "signed_message_header": "BitZeny Signed Message:\n", "slip44": 123, "support": {"connect": false, "trezor1": "1.8.2", "trezor2": "2.1.1", "webwallet": false}, "uri_prefix": "bitzeny", "website": "https://bitzeny.tech", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 25, "address_type_p2sh": 5, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 300, "cashaddr_prefix": null, "coin_label": "Bitcloud", "coin_name": "Bitcloud", "coin_shortcut": "BTDX", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 5460, "force_bip143": false, "fork_id": null, "github": "https://github.com/LIMXTEC/Bitcloud", "hash_genesis_block": "000002d56463941c20eae5cb474cc805b646515d18bc7dc222a0885b206eadb0", "key": "bitcoin:BTDX", "maintainer": "limxdev ", "max_address_length": 34, "maxfee_kb": 1000000, "min_address_length": 27, "minfee_kb": 10000, "name": "Bitcloud", "segwit": false, "shortcut": "BTDX", "signed_message_header": "Diamond Signed Message:\n", "slip44": 218, "support": {"connect": true, "trezor1": "1.7.2", "trezor2": "2.0.10", "webwallet": false}, "uri_prefix": "bitcloud", "website": "https://bit-cloud.info", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 0, "address_type_p2sh": 5, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://bch1.trezor.io", "https://bch2.trezor.io", "https://bch3.trezor.io", "https://bch4.trezor.io", "https://bch5.trezor.io"], "blocktime_seconds": 600, "cashaddr_prefix": "bitcoincash", "coin_label": "Bitcoin Cash", "coin_name": "Bcash", "coin_shortcut": "BCH", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 70, "High": 200, "Low": 10, "Normal": 140}, "dust_limit": 546, "force_bip143": true, "fork_id": 0, "github": "https://github.com/Bitcoin-ABC/bitcoin-abc", "hash_genesis_block": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", "key": "bitcoin:BCH", "maintainer": "Jochen Hoenicke ", "max_address_length": 34, "maxfee_kb": 500000, "min_address_length": 27, "minfee_kb": 1000, "name": "Bitcoin Cash", "segwit": false, "shortcut": "BCH", "signed_message_header": "Bitcoin Signed Message:\n", "slip44": 145, "support": {"connect": true, "trezor1": "1.6.2", "trezor2": "2.0.7", "webwallet": true}, "uri_prefix": "bitcoincash", "website": "https://www.bitcoincash.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 111, "address_type_p2sh": 196, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 600, "cashaddr_prefix": "bchtest", "coin_label": "Bitcoin Cash Testnet", "coin_name": "Bcash Testnet", "coin_shortcut": "TBCH", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": true, "fork_id": 0, "github": "https://github.com/Bitcoin-ABC/bitcoin-abc", "hash_genesis_block": "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943", "key": "bitcoin:TBCH", "maintainer": "Jochen Hoenicke ", "max_address_length": 34, "maxfee_kb": 10000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Bitcoin Cash Testnet", "segwit": false, "shortcut": "TBCH", "signed_message_header": "Bitcoin Signed Message:\n", "slip44": 1, "support": {"connect": true, "trezor1": "1.6.2", "trezor2": "2.0.7", "webwallet": false}, "uri_prefix": "bitcoincash", "website": "https://www.bitcoincash.org", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 38, "address_type_p2sh": 23, "bech32_prefix": "btg", "bip115": false, "bitcore": [], "blockbook": ["https://btg1.trezor.io", "https://btg2.trezor.io", "https://btg3.trezor.io", "https://btg4.trezor.io", "https://btg5.trezor.io"], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Bitcoin Gold", "coin_name": "Bgold", "coin_shortcut": "BTG", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 70, "High": 200, "Low": 10, "Normal": 140}, "dust_limit": 546, "force_bip143": true, "fork_id": 79, "github": "https://github.com/BTCGPU/BTCGPU", "hash_genesis_block": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", "key": "bitcoin:BTG", "maintainer": "Saleem Rashid ", "max_address_length": 34, "maxfee_kb": 500000, "min_address_length": 27, "minfee_kb": 1000, "name": "Bitcoin Gold", "segwit": true, "shortcut": "BTG", "signed_message_header": "Bitcoin Gold Signed Message:\n", "slip44": 156, "support": {"connect": true, "trezor1": "1.6.2", "trezor2": "2.0.7", "webwallet": true}, "uri_prefix": "bitcoingold", "website": "https://bitcoingold.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 111, "address_type_p2sh": 196, "bech32_prefix": "tbtg", "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Bitcoin Gold Testnet", "coin_name": "Bgold Testnet", "coin_shortcut": "TBTG", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 70, "High": 200, "Low": 10, "Normal": 140}, "dust_limit": 546, "force_bip143": true, "fork_id": 79, "github": "https://github.com/BTCGPU/BTCGPU", "hash_genesis_block": "00000000e0781ebe24b91eedc293adfea2f557b53ec379e78959de3853e6f9f6", "key": "bitcoin:TBTG", "maintainer": "The Bitcoin Gold Developers ", "max_address_length": 34, "maxfee_kb": 500000, "min_address_length": 27, "minfee_kb": 1000, "name": "Bitcoin Gold Testnet", "segwit": true, "shortcut": "TBTG", "signed_message_header": "Bitcoin Gold Signed Message:\n", "slip44": 156, "support": {"connect": true, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "bitcoingold", "website": "https://bitcoingold.org", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": 73342198, "xpub_magic_segwit_p2sh": 71979618}, {"address_type": 4901, "address_type_p2sh": 5039, "bech32_prefix": null, "bip115": false, "bitcore": ["https://explorer.btcprivate.org"], "blockbook": [], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Bitcoin Private", "coin_name": "Bprivate", "coin_shortcut": "BTCP", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": 42, "github": "https://github.com/BTCPrivate/BitcoinPrivate", "hash_genesis_block": "0007104ccda289427919efc39dc9e4d499804b7bebc22df55f8b834301260602", "key": "bitcoin:BTCP", "maintainer": "Chris Sulmone ", "max_address_length": 95, "maxfee_kb": 1000000, "min_address_length": 35, "minfee_kb": 1000, "name": "Bitcoin Private", "segwit": false, "shortcut": "BTCP", "signed_message_header": "BitcoinPrivate Signed Message:\n", "slip44": 183, "support": {"connect": true, "trezor1": "1.6.2", "trezor2": "2.0.7", "webwallet": true}, "uri_prefix": "bitcoinprivate", "website": "https://btcprivate.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 61, "address_type_p2sh": 123, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://blockbook1.bitcoinrh.org", "https://blockbook2.bitcoinrh.org"], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Bitcoin Rhodium", "coin_name": "Brhodium", "coin_shortcut": "XRC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 70, "High": 200, "Low": 10, "Normal": 140}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://gitlab.com/bitcoinrh/BRhodiumNode", "hash_genesis_block": "baff5bfd9dc43fb672d003ec20fd21428f9282ca46bfa1730d73e1f2c75f5fdd", "key": "bitcoin:XRC", "maintainer": "baff5b ", "max_address_length": 34, "maxfee_kb": 2000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Bitcoin Rhodium", "segwit": false, "shortcut": "XRC", "signed_message_header": "BitCoin Rhodium Signed Message:\n", "slip44": 10291, "support": {"connect": false, "trezor1": "soon", "trezor2": "2.1.1", "webwallet": false}, "uri_prefix": "bitcoin-rhodium", "website": "https://www.bitcoinrh.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 3, "address_type_p2sh": 125, "bech32_prefix": "btx", "bip115": false, "bitcore": ["https://insight.bitcore.cc"], "blockbook": [], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Bitcore", "coin_name": "Bitcore", "coin_shortcut": "BTX", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Low": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/LIMXTEC/BitCore", "hash_genesis_block": "604148281e5c4b7f2487e5d03cd60d8e6f69411d613f6448034508cea52e9574", "key": "bitcoin:BTX", "maintainer": "limxdev ", "max_address_length": 34, "maxfee_kb": 2000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Bitcore", "segwit": true, "shortcut": "BTX", "signed_message_header": "BitCore Signed Message:\n", "slip44": 160, "support": {"connect": true, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "bitcore", "website": "https://bitcore.cc", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 102, "address_type_p2sh": 5, "bech32_prefix": "bsd", "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 200, "cashaddr_prefix": null, "coin_label": "Bitsend", "coin_name": "Bitsend", "coin_shortcut": "BSD", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 5460, "force_bip143": false, "fork_id": null, "github": "https://github.com/LIMXTEC/BitSend", "hash_genesis_block": "0000012e1b8843ac9ce8c18603658eaf8895f99d3f5e7e1b7b1686f35e3c087a", "key": "bitcoin:BSD", "maintainer": "limxdev ", "max_address_length": 34, "maxfee_kb": 1000000, "min_address_length": 27, "minfee_kb": 10000, "name": "Bitsend", "segwit": true, "shortcut": "BSD", "signed_message_header": "Bitsend Signed Message:\n", "slip44": 91, "support": {"connect": true, "trezor1": "1.7.2", "trezor2": "2.0.10", "webwallet": false}, "uri_prefix": "bitsend", "website": "https://bitsend.info", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 26, "address_type_p2sh": 5, "bech32_prefix": "bst", "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "BlockStamp", "coin_name": "BlockStamp", "coin_shortcut": "BST", "consensus_branch_id": null, "cooldown": 1000, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 70, "High": 200, "Low": 10, "Normal": 140}, "duplicate": true, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/BlockStamp/bst", "hash_genesis_block": "8000000049a2e26b0185be50b4b8ed58b707c8893762959f0b1673641cae1828", "key": "bitcoin:BST", "maintainer": "Krzysztof Kuchta ", "max_address_length": 34, "maxfee_kb": 2000000, "min_address_length": 27, "minfee_kb": 1000, "name": "BlockStamp", "segwit": true, "shortcut": "BST", "signed_message_header": "BST Signed Message:\n", "slip44": 254, "support": {"connect": false, "trezor1": "soon", "trezor2": "2.1.1", "webwallet": false}, "uri_prefix": "blockstamp", "website": "https://blockstamp.info", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 28, "address_type_p2sh": 35, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://blockbook.capricoin.org", "https://blockbook2.capricoin.org", "https://blockbook3.capricoin.org", "https://blockbook4.capricoin.org"], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Capricoin", "coin_name": "Capricoin", "coin_shortcut": "CPC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 7, "High": 20, "Low": 1, "Normal": 14}, "duplicate": true, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/Capricoinofficial/Capricoin", "hash_genesis_block": "00000d23fa0fc52c90893adb1181c9ddffb6c797a3e41864b9a23aa2f2981fe3", "key": "bitcoin:CPC", "maintainer": "Tibor Arpas ", "max_address_length": 34, "maxfee_kb": 2000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Capricoin", "segwit": false, "shortcut": "CPC", "signed_message_header": "Capricoin Signed Message:\n", "slip44": 289, "support": {"connect": true, "trezor1": false, "trezor2": "2.0.10", "webwallet": false}, "uri_prefix": "capricoin", "website": "https://capricoin.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 95495, "address_type_p2sh": 95473, "bech32_prefix": null, "bip115": false, "bitcore": ["https://insight-01.crown.tech", "https://insight-02.crown.tech", "https://insight-03.crown.tech"], "blockbook": [], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Crown", "coin_name": "Crown", "coin_shortcut": "CRW", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/Crowndev/crowncoin", "hash_genesis_block": "0000000085370d5e122f64f4ab19c68614ff3df78c8d13cb814fd7e69a1dc6da", "key": "bitcoin:CRW", "maintainer": "Ashot ", "max_address_length": 40, "maxfee_kb": 2000000, "min_address_length": 36, "minfee_kb": 1000, "name": "Crown", "segwit": false, "shortcut": "CRW", "signed_message_header": "Crown Signed Message:\n", "slip44": 72, "support": {"connect": false, "trezor1": false, "trezor2": false, "webwallet": false}, "uri_prefix": "crown", "website": "https://crown.tech", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 76, "address_type_p2sh": 16, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://dash1.trezor.io", "https://dash2.trezor.io", "https://dash3.trezor.io", "https://dash4.trezor.io", "https://dash5.trezor.io"], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Dash", "coin_name": "Dash", "coin_shortcut": "DASH", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 5460, "force_bip143": false, "fork_id": null, "github": "https://github.com/dashpay/dash", "hash_genesis_block": "00000ffd590b1485b3caadc19b22e6379c733355108f107a430458cdf3407ab6", "key": "bitcoin:DASH", "maintainer": "Karel Bilek ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 1000, "name": "Dash", "segwit": false, "shortcut": "DASH", "signed_message_header": "DarkCoin Signed Message:\n", "slip44": 5, "support": {"connect": true, "trezor1": "1.5.2", "trezor2": "2.0.5", "webwallet": true}, "uri_prefix": "dash", "website": "https://www.dash.org", "xprv_magic": 50221816, "xpub_magic": 50221772, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 140, "address_type_p2sh": 19, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Dash Testnet", "coin_name": "Dash Testnet", "coin_shortcut": "tDASH", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 5460, "force_bip143": false, "fork_id": null, "github": "https://github.com/dashpay/dash", "hash_genesis_block": "00000bafbc94add76cb75e2ec92894837288a481e5c005f6563d91623bf8bc2c", "key": "bitcoin:tDASH", "maintainer": "Karel Bilek ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 10000, "name": "Dash Testnet", "segwit": false, "shortcut": "tDASH", "signed_message_header": "DarkCoin Signed Message:\n", "slip44": 1, "support": {"connect": true, "trezor1": "1.6.2", "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "dash", "website": "https://www.dash.org", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 1855, "address_type_p2sh": 1818, "bech32_prefix": null, "bip115": false, "bitcore": ["https://mainnet.decred.org"], "blockbook": [], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Decred", "coin_name": "Decred", "coin_shortcut": "DCR", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1_decred", "decred": true, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/decred/dcrd", "hash_genesis_block": "298e5cc3d985bfe7f81dc135f360abe089edd4396b86d2de66b0cef42b21d980", "key": "bitcoin:DCR", "maintainer": "Alex Yocom-Piatt ", "max_address_length": 35, "maxfee_kb": 1000000, "min_address_length": 35, "minfee_kb": 10000, "name": "Decred", "segwit": false, "shortcut": "DCR", "signed_message_header": "Decred Signed Message:\n", "slip44": 42, "support": {"connect": false, "trezor1": "1.6.2", "trezor2": "2.0.8", "webwallet": true}, "uri_prefix": "bitcoin", "website": "https://www.decred.org", "xprv_magic": 50177256, "xpub_magic": 50178342, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 3873, "address_type_p2sh": 3836, "bech32_prefix": null, "bip115": false, "bitcore": ["https://testnet.decred.org"], "blockbook": [], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Decred Testnet", "coin_name": "Decred Testnet", "coin_shortcut": "TDCR", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1_decred", "decred": true, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/decred/dcrd", "hash_genesis_block": "a649dce53918caf422e9c711c858837e08d626ecfcd198969b24f7b634a49bac", "key": "bitcoin:TDCR", "maintainer": "Saleem Rashid ", "max_address_length": 35, "maxfee_kb": 10000000, "min_address_length": 35, "minfee_kb": 1000, "name": "Decred Testnet", "segwit": false, "shortcut": "TDCR", "signed_message_header": "Decred Signed Message:\n", "slip44": 1, "support": {"connect": false, "trezor1": "1.6.2", "trezor2": "2.0.8", "webwallet": true}, "uri_prefix": "bitcoin", "website": "https://www.decred.org", "xprv_magic": 70615959, "xpub_magic": 70617041, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 30, "address_type_p2sh": 90, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 30, "cashaddr_prefix": null, "coin_label": "Denarius", "coin_name": "Denarius", "coin_shortcut": "DNR", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 54600, "force_bip143": false, "fork_id": null, "github": "https://github.com/carsenk/denarius", "hash_genesis_block": "00000d5dbbda01621cfc16bbc1f9bf3264d641a5dbf0de89fd0182c2c4828fcd", "key": "bitcoin:DNR", "maintainer": "carsenk ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 10000, "name": "Denarius", "segwit": false, "shortcut": "DNR", "signed_message_header": "Denarius Signed Message:\n", "slip44": 116, "support": {"connect": true, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "denarius", "website": "https://denarius.io", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 30, "address_type_p2sh": 63, "bech32_prefix": "dgb", "bip115": false, "bitcore": [], "blockbook": ["https://dgb1.trezor.io", "https://dgb2.trezor.io"], "blocktime_seconds": 15, "cashaddr_prefix": null, "coin_label": "DigiByte", "coin_name": "DigiByte", "coin_shortcut": "DGB", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 70, "High": 200, "Low": 10, "Normal": 140}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/digibyte/digibyte", "hash_genesis_block": "7497ea1b465eb39f1c8f507bc877078fe016d6fcb6dfad3a64c98dcc6e1e8496", "key": "bitcoin:DGB", "maintainer": "DigiByte ", "max_address_length": 34, "maxfee_kb": 500000, "min_address_length": 27, "minfee_kb": 1000, "name": "DigiByte", "segwit": true, "shortcut": "DGB", "signed_message_header": "DigiByte Signed Message:\n", "slip44": 20, "support": {"connect": true, "trezor1": "1.6.3", "trezor2": "2.0.7", "webwallet": true}, "uri_prefix": "digibyte", "website": "https://digibyte.io", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 30, "address_type_p2sh": 22, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://doge1.trezor.io", "https://doge2.trezor.io", "https://doge3.trezor.io", "https://doge4.trezor.io", "https://doge5.trezor.io"], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Dogecoin", "coin_name": "Dogecoin", "coin_shortcut": "DOGE", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 100000}, "dust_limit": 10000000, "force_bip143": false, "fork_id": null, "github": "https://github.com/dogecoin/dogecoin", "hash_genesis_block": "1a91e3dace36e2be3bf030a65679fe821aa1d6ef92e7c9902eb318182c355691", "key": "bitcoin:DOGE", "maintainer": "Karel Bilek ", "max_address_length": 34, "maxfee_kb": 1000000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Dogecoin", "segwit": false, "shortcut": "DOGE", "signed_message_header": "Dogecoin Signed Message:\n", "slip44": 3, "support": {"connect": true, "trezor1": "1.5.2", "trezor2": "2.0.5", "webwallet": true}, "uri_prefix": "dogecoin", "website": "https://dogecoin.com", "xprv_magic": 49988504, "xpub_magic": 49990397, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 235, "address_type_p2sh": 75, "bech32_prefix": "ert", "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Elements", "coin_name": "Elements", "coin_shortcut": "ELEMENTS", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/ElementsProject/elements", "hash_genesis_block": "209577bda6bf4b5804bd46f8621580dd6d4e8bfa2d190e1c50e932492baca07d", "key": "bitcoin:ELEMENTS", "maintainer": "Roman Zeyde ", "max_address_length": 34, "maxfee_kb": 10000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Elements", "segwit": true, "shortcut": "ELEMENTS", "signed_message_header": "Bitcoin Signed Message:\n", "slip44": 1, "support": {"connect": false, "trezor1": null, "trezor2": null, "webwallet": false}, "uri_prefix": "elements", "website": "https://elementsproject.org", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": 73342198, "xpub_magic_segwit_p2sh": 71979618}, {"address_type": 95, "address_type_p2sh": 36, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 180, "cashaddr_prefix": null, "coin_label": "FairCoin", "coin_name": "FairCoin", "coin_shortcut": "FAIR", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 800000}, "dust_limit": 500000, "force_bip143": false, "fork_id": 0, "github": "https://github.com/faircoin/faircoin", "hash_genesis_block": "beed44fa5e96150d95d56ebd5d2625781825a9407a5215dd7eda723373a0a1d7", "key": "bitcoin:FAIR", "maintainer": "Santi Nore\u00f1a ", "max_address_length": 34, "maxfee_kb": 10000000, "min_address_length": 27, "minfee_kb": 1000, "name": "FairCoin", "segwit": false, "shortcut": "FAIR", "signed_message_header": "FairCoin Signed Message:\n", "slip44": 298, "support": {"connect": false, "trezor1": "soon", "trezor2": "2.1.1", "webwallet": false}, "uri_prefix": "faircoin", "website": "https://www.faircoin.world", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 14, "address_type_p2sh": 5, "bech32_prefix": "fc", "bip115": false, "bitcore": ["https://bitcore.feathercoin.com"], "blockbook": [], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Feathercoin", "coin_name": "Feathercoin", "coin_shortcut": "FTC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 1000}, "duplicate": true, "dust_limit": 54600, "force_bip143": false, "fork_id": null, "github": "https://github.com/FeatherCoin/Feathercoin", "hash_genesis_block": "12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2", "key": "bitcoin:FTC", "maintainer": "Lucas Betschart ", "max_address_length": 34, "maxfee_kb": 40000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Feathercoin", "segwit": true, "shortcut": "FTC", "signed_message_header": "Feathercoin Signed Message:\n", "slip44": 8, "support": {"connect": true, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "feathercoin", "website": "https://feathercoin.com", "xprv_magic": 76077806, "xpub_magic": 76069926, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 35, "address_type_p2sh": 94, "bech32_prefix": "flo", "bip115": false, "bitcore": ["https://livenet.flocha.in"], "blockbook": [], "blocktime_seconds": 40, "cashaddr_prefix": null, "coin_label": "Flo", "coin_name": "Florincoin", "coin_shortcut": "FLO", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 1000}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/floblockchain/flo", "hash_genesis_block": "09c7781c9df90708e278c35d38ea5c9041d7ecfcdd1c56ba67274b7cff3e1cea", "key": "bitcoin:FLO", "maintainer": "Robert English ", "max_address_length": 34, "maxfee_kb": 40000000, "min_address_length": 27, "minfee_kb": 100000, "name": "Flo", "segwit": true, "shortcut": "FLO", "signed_message_header": "Florincoin Signed Message:\n", "slip44": 216, "support": {"connect": true, "trezor1": "1.7.2", "trezor2": "2.0.11", "webwallet": false}, "uri_prefix": "florincoin", "website": "https://flo.cash", "xprv_magic": 15264107, "xpub_magic": 1526049, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 28471030}, {"address_type": 36, "address_type_p2sh": 16, "bech32_prefix": "fc", "bip115": false, "bitcore": [], "blockbook": ["https://explorer.fujicoin.org"], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Fujicoin", "coin_name": "Fujicoin", "coin_shortcut": "FJC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 20000, "High": 100000, "Low": 10000, "Normal": 50000}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/fujicoin/fujicoin", "hash_genesis_block": "adb6d9cfd74075e7f91608add4bd2a2ea636f70856183086842667a1597714a0", "key": "bitcoin:FJC", "maintainer": "motty ", "max_address_length": 34, "maxfee_kb": 1000000000, "min_address_length": 27, "minfee_kb": 10000000, "name": "Fujicoin", "segwit": true, "shortcut": "FJC", "signed_message_header": "FujiCoin Signed Message:\n", "slip44": 75, "support": {"connect": true, "trezor1": "1.6.1", "trezor2": "2.0.5", "webwallet": true}, "uri_prefix": "fujicoin", "website": "https://fujicoin.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 38, "address_type_p2sh": 10, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://blockbook.gincoin.io"], "blocktime_seconds": 120, "cashaddr_prefix": null, "coin_label": "GIN", "coin_name": "Gincoin", "coin_shortcut": "GIN", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 5460, "force_bip143": false, "fork_id": null, "github": "https://github.com/gincoin-dev/gincoin-core", "hash_genesis_block": "00000cd6bde619b2c3b23ad2e384328a450a37fa28731debf748c3b17f91f97d", "key": "bitcoin:GIN", "maintainer": "Dragos Badea ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 1000, "name": "GIN", "segwit": false, "shortcut": "GIN", "signed_message_header": "DarkCoin Signed Message:\n", "slip44": 2000, "support": {"connect": true, "trezor1": "1.7.2", "trezor2": "2.0.11", "webwallet": false}, "uri_prefix": "gincoin", "website": "https://gincoin.io", "xprv_magic": 50221816, "xpub_magic": 50221772, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 38, "address_type_p2sh": 62, "bech32_prefix": "game", "bip115": false, "bitcore": [], "blockbook": ["https://blockbook.gamecredits.network"], "blocktime_seconds": 90, "cashaddr_prefix": null, "coin_label": "GameCredits", "coin_name": "GameCredits", "coin_shortcut": "GAME", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 1000}, "dust_limit": 54600, "force_bip143": false, "fork_id": null, "github": "https://github.com/gamecredits-project/gamecredits", "hash_genesis_block": "91ec5f25ee9a0ffa1af7d4da4db9a552228dd2dc77cdb15b738be4e1f55f30ee", "key": "bitcoin:GAME", "maintainer": "Samad Sajanlal ", "max_address_length": 34, "maxfee_kb": 5000000, "min_address_length": 27, "minfee_kb": 100000, "name": "GameCredits", "segwit": true, "shortcut": "GAME", "signed_message_header": "GameCredits Signed Message:\n", "slip44": 101, "support": {"connect": true, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "gamecredits", "website": "https://gamecredits.org", "xprv_magic": 27108450, "xpub_magic": 27106558, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 28471030}, {"address_type": 36, "address_type_p2sh": 5, "bech32_prefix": "grs", "bip115": false, "bitcore": ["https://groestlsight.groestlcoin.org", "https://grsblocks.com"], "blockbook": ["https://blockbook.groestlcoin.org"], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Groestlcoin", "coin_name": "Groestlcoin", "coin_shortcut": "GRS", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1_groestl", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/Groestlcoin/groestlcoin", "hash_genesis_block": "00000ac5927c594d49cc0bdb81759d0da8297eb614683d3acb62f0703b639023", "key": "bitcoin:GRS", "maintainer": "Yura Pakhuchiy ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 1000, "name": "Groestlcoin", "segwit": true, "shortcut": "GRS", "signed_message_header": "GroestlCoin Signed Message:\n", "slip44": 17, "support": {"connect": false, "trezor1": "1.6.2", "trezor2": "2.0.8", "webwallet": true}, "uri_prefix": "groestlcoin", "website": "https://www.groestlcoin.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 111, "address_type_p2sh": 196, "bech32_prefix": "tgrs", "bip115": false, "bitcore": ["https://groestlsight-test.groestlcoin.org"], "blockbook": ["https://blockbook-test.groestlcoin.org"], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Groestlcoin Testnet", "coin_name": "Groestlcoin Testnet", "coin_shortcut": "tGRS", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1_groestl", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/Groestlcoin/groestlcoin", "hash_genesis_block": "000000ffbb50fc9898cdd36ec163e6ba23230164c0052a28876255b7dcf2cd36", "key": "bitcoin:tGRS", "maintainer": "Yura Pakhuchiy ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 1000, "name": "Groestlcoin Testnet", "segwit": true, "shortcut": "tGRS", "signed_message_header": "GroestlCoin Signed Message:\n", "slip44": 1, "support": {"connect": false, "trezor1": "1.6.2", "trezor2": "2.0.8", "webwallet": true}, "uri_prefix": "groestlcoin", "website": "https://www.groestlcoin.org", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": 73342198, "xpub_magic_segwit_p2sh": 71979618}, {"address_type": 8329, "address_type_p2sh": 8342, "bech32_prefix": null, "bip115": true, "bitcore": ["https://explorer.horizen.global"], "blockbook": [], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Horizen", "coin_name": "Horizen", "coin_shortcut": "ZEN", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/ZencashOfficial/zen", "hash_genesis_block": "0007104ccda289427919efc39dc9e4d499804b7bebc22df55f8b834301260602", "key": "bitcoin:ZEN", "maintainer": "Power_VANO ", "max_address_length": 95, "maxfee_kb": 2000000, "min_address_length": 35, "minfee_kb": 1000, "name": "Horizen", "segwit": false, "shortcut": "ZEN", "signed_message_header": "Zcash Signed Message:\n", "slip44": 121, "support": {"connect": true, "trezor1": false, "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "horizen", "website": "https://www.horizen.global", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 60, "address_type_p2sh": 85, "bech32_prefix": null, "bip115": false, "bitcore": ["https://api.kmd.dev"], "blockbook": [], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Komodo", "coin_name": "Komodo", "coin_shortcut": "KMD", "consensus_branch_id": {"1": 0, "2": 0, "3": 1537743641, "4": 1991772603}, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/komodoplatform/komodo", "hash_genesis_block": "027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71", "key": "bitcoin:KMD", "maintainer": "Kadan Stadelmann ", "max_address_length": 34, "maxfee_kb": 1000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Komodo", "segwit": false, "shortcut": "KMD", "signed_message_header": "Komodo Signed Message:\n", "slip44": 141, "support": {"connect": true, "trezor1": "1.8.0", "trezor2": "2.0.11", "webwallet": false}, "uri_prefix": "komodo", "website": "https://komodoplatform.com", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 6198, "address_type_p2sh": 6203, "bech32_prefix": null, "bip115": false, "bitcore": ["https://insight.kotocoin.info"], "blockbook": [], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Koto", "coin_name": "Koto", "coin_shortcut": "KOTO", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/KotoDevelopers/koto", "hash_genesis_block": "6d424c350729ae633275d51dc3496e16cd1b1d195c164da00f39c499a2e9959e", "key": "bitcoin:KOTO", "maintainer": "WO ", "max_address_length": 95, "maxfee_kb": 1000000, "min_address_length": 35, "minfee_kb": 1000, "name": "Koto", "segwit": false, "shortcut": "KOTO", "signed_message_header": "Koto Signed Message:\n", "slip44": 510, "support": {"connect": true, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": true}, "uri_prefix": "koto", "website": "https://ko-to.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 48, "address_type_p2sh": 50, "bech32_prefix": "ltc", "bip115": false, "bitcore": [], "blockbook": ["https://ltc1.trezor.io", "https://ltc2.trezor.io", "https://ltc3.trezor.io", "https://ltc4.trezor.io", "https://ltc5.trezor.io"], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Litecoin", "coin_name": "Litecoin", "coin_shortcut": "LTC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 1000}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/litecoin-project/litecoin", "hash_genesis_block": "12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2", "key": "bitcoin:LTC", "maintainer": "Pavol Rusnak ", "max_address_length": 34, "maxfee_kb": 40000000, "min_address_length": 27, "minfee_kb": 100000, "name": "Litecoin", "segwit": true, "shortcut": "LTC", "signed_message_header": "Litecoin Signed Message:\n", "slip44": 2, "support": {"connect": true, "trezor1": "1.5.2", "trezor2": "2.0.5", "webwallet": true}, "uri_prefix": "litecoin", "website": "https://litecoin.org", "xprv_magic": 27106558, "xpub_magic": 27108450, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 28471030}, {"address_type": 111, "address_type_p2sh": 58, "bech32_prefix": "tltc", "bip115": false, "bitcore": ["https://testnet.litecore.io"], "blockbook": [], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Litecoin Testnet", "coin_name": "Litecoin Testnet", "coin_shortcut": "tLTC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 54600, "force_bip143": false, "fork_id": null, "github": "https://github.com/litecoin-project/litecoin", "hash_genesis_block": "4966625a4b2851d9fdee139e56211a0d88575f59ed816ff5e6a63deb4e3e29a0", "key": "bitcoin:tLTC", "maintainer": "Pavol Rusnak ", "max_address_length": 34, "maxfee_kb": 40000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Litecoin Testnet", "segwit": true, "shortcut": "tLTC", "signed_message_header": "Litecoin Signed Message:\n", "slip44": 1, "support": {"connect": true, "trezor1": "1.6.2", "trezor2": "2.0.7", "webwallet": true}, "uri_prefix": "litecoin", "website": "https://litecoin.org", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": 73342198, "xpub_magic_segwit_p2sh": 71979618}, {"address_type": 50, "address_type_p2sh": 5, "bech32_prefix": "mec", "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Megacoin", "coin_name": "Megacoin", "coin_shortcut": "MEC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Low": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/LIMXTEC/Megacoin", "hash_genesis_block": "7520788e2d99eec7cf6cf7315577e1268e177fff94cb0a7caf6a458ceeea9ac2", "key": "bitcoin:MEC", "maintainer": "limxdev ", "max_address_length": 34, "maxfee_kb": 1000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Megacoin", "segwit": true, "shortcut": "MEC", "signed_message_header": "MegaCoin Signed Message:\n", "slip44": 217, "support": {"connect": true, "trezor1": "1.7.2", "trezor2": "2.0.10", "webwallet": false}, "uri_prefix": "megacoin", "website": "https://www.megacoin.eu", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 50, "address_type_p2sh": 55, "bech32_prefix": "mona", "bip115": false, "bitcore": ["https://mona.chainsight.info", "https://insight.electrum-mona.org"], "blockbook": ["https://blockbook.electrum-mona.org"], "blocktime_seconds": 90, "cashaddr_prefix": null, "coin_label": "Monacoin", "coin_name": "Monacoin", "coin_shortcut": "MONA", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 1000}, "dust_limit": 54600, "force_bip143": false, "fork_id": null, "github": "https://github.com/monacoinproject/monacoin", "hash_genesis_block": "ff9f1c0116d19de7c9963845e129f9ed1bfc0b376eb54fd7afa42e0d418c8bb6", "key": "bitcoin:MONA", "maintainer": "cryptcoin-junkey ", "max_address_length": 34, "maxfee_kb": 5000000, "min_address_length": 27, "minfee_kb": 100000, "name": "Monacoin", "segwit": true, "shortcut": "MONA", "signed_message_header": "Monacoin Signed Message:\n", "slip44": 22, "support": {"connect": true, "trezor1": "1.6.0", "trezor2": "2.0.5", "webwallet": true}, "uri_prefix": "monacoin", "website": "https://monacoin.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 16, "address_type_p2sh": 76, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://blockbook.monetaryunit.org"], "blocktime_seconds": 40, "cashaddr_prefix": null, "coin_label": "MonetaryUnit", "coin_name": "MonetaryUnit", "coin_shortcut": "MUE", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 5460, "force_bip143": false, "fork_id": null, "github": "https://github.com/muecoin/MUE", "hash_genesis_block": "0b58ed450b3819ca54ab0054c4d220ca4f887d21c9e55d2a333173adf76d987f", "key": "bitcoin:MUE", "maintainer": "Sotiris Blad ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 1000, "name": "MonetaryUnit", "segwit": false, "shortcut": "MUE", "signed_message_header": "MonetaryUnit Signed Message:\n", "slip44": 31, "support": {"connect": true, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "monetaryunit", "website": "https://www.monetaryunit.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 50, "address_type_p2sh": 9, "bech32_prefix": "my", "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Myriad", "coin_name": "Myriad", "coin_shortcut": "XMY", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 70, "High": 200, "Low": 10, "Normal": 140}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/myriadteam/myriadcoin", "hash_genesis_block": "00000ffde4c020b5938441a0ea3d314bf619eff0b38f32f78f7583cffa1ea485", "key": "bitcoin:XMY", "maintainer": "Adam Hickerson ", "max_address_length": 34, "maxfee_kb": 2000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Myriad", "segwit": true, "shortcut": "XMY", "signed_message_header": "Myriadcoin Signed Message:\n", "slip44": 90, "support": {"connect": true, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "myriadcoin", "website": "https://www.myriadcoin.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 38, "address_type_p2sh": 53, "bech32_prefix": "nix", "bip115": false, "bitcore": ["https://blockchain.nixplatform.io"], "blockbook": [], "blocktime_seconds": 120, "cashaddr_prefix": null, "coin_label": "NIX", "coin_name": "NIX", "coin_shortcut": "NIX", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 1000}, "dust_limit": 54600, "force_bip143": false, "fork_id": null, "github": "https://github.com/nixplatform/nixcore", "hash_genesis_block": "dd28ad86def767c3cfc34267a950d871fc7462bc57ea4a929fc3596d9b598e41", "key": "bitcoin:NIX", "maintainer": "mattt21 ", "max_address_length": 34, "maxfee_kb": 40000000, "min_address_length": 27, "minfee_kb": 0, "name": "NIX", "segwit": true, "shortcut": "NIX", "signed_message_header": "NIX Signed Message:\n", "slip44": 400, "support": {"connect": true, "trezor1": "1.7.2", "trezor2": "2.0.11", "webwallet": false}, "uri_prefix": "nix", "website": "https://nixplatform.io", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 52, "address_type_p2sh": 5, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://nmc1.trezor.io", "https://nmc2.trezor.io"], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Namecoin", "coin_name": "Namecoin", "coin_shortcut": "NMC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 2940, "force_bip143": false, "fork_id": null, "github": "https://github.com/namecoin/namecoin-core", "hash_genesis_block": "000000000062b72c5e2ceb45fbc8587e807c155b0da735e6483dfba2f0a9c770", "key": "bitcoin:NMC", "maintainer": "Pavol Rusnak ", "max_address_length": 34, "maxfee_kb": 10000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Namecoin", "segwit": false, "shortcut": "NMC", "signed_message_header": "Namecoin Signed Message:\n", "slip44": 7, "support": {"connect": true, "trezor1": "1.5.2", "trezor2": "2.0.5", "webwallet": true}, "uri_prefix": "namecoin", "website": "https://namecoin.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 30, "address_type_p2sh": 13, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://blockbook.pivx.link"], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "PIVX", "coin_name": "PIVX", "coin_shortcut": "PIVX", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/PIVX-Project/PIVX", "hash_genesis_block": "0000041e482b9b9691d98eefb48473405c0b8ec31b76df3797c74a78680ef818", "key": "bitcoin:PIVX", "maintainer": "Random Zebra ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 100, "name": "PIVX", "segwit": false, "shortcut": "PIVX", "signed_message_header": "DarkNet Signed Message:\n", "slip44": 119, "support": {"connect": true, "trezor1": "1.8.0", "trezor2": "2.0.11", "webwallet": false}, "uri_prefix": "pivx", "website": "https://pivx.org", "xprv_magic": 35729707, "xpub_magic": 36513075, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 139, "address_type_p2sh": 19, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://blockbook-testnet.pivx.link"], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "PIVX Testnet", "coin_name": "PIVX Testnet", "coin_shortcut": "tPIVX", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 54600, "force_bip143": false, "fork_id": null, "github": "https://github.com/PIVX-Project/PIVX", "hash_genesis_block": "0000041e482b9b9691d98eefb48473405c0b8ec31b76df3797c74a78680ef818", "key": "bitcoin:tPIVX", "maintainer": "Random Zebra ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 100, "name": "PIVX Testnet", "segwit": false, "shortcut": "tPIVX", "signed_message_header": "DarkNet Signed Message:\n", "slip44": 1, "support": {"connect": true, "trezor1": "1.8.0", "trezor2": "2.0.11", "webwallet": false}, "uri_prefix": "pivx", "website": "https://pivx.org", "xprv_magic": 981489719, "xpub_magic": 981492128, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 47, "address_type_p2sh": 22, "bech32_prefix": null, "bip115": false, "bitcore": ["https://live.pesetacoin.info"], "blockbook": [], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Pesetacoin", "coin_name": "Pesetacoin", "coin_shortcut": "PTC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "duplicate": true, "dust_limit": 10000000, "force_bip143": false, "fork_id": null, "github": "https://github.com/FundacionPesetacoin/PesetacoinCore", "hash_genesis_block": "edfe5830b53251bfff733600b1cd5c192e761c011b055f07924634818c906438", "key": "bitcoin:PTC", "maintainer": "Rw ", "max_address_length": 34, "maxfee_kb": 1000000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Pesetacoin", "segwit": false, "shortcut": "PTC", "signed_message_header": "Pesetacoin Signed Message:\n", "slip44": 109, "support": {"connect": true, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "pesetacoin", "website": "https://pesetacoin.info", "xprv_magic": 76079604, "xpub_magic": 76071982, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 55, "address_type_p2sh": 56, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://blockbook.polispay.org"], "blocktime_seconds": 120, "cashaddr_prefix": null, "coin_label": "Polis", "coin_name": "Polis", "coin_shortcut": "POLIS", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 5460, "force_bip143": false, "fork_id": null, "github": "https://github.com/polispay/polis", "hash_genesis_block": "000009701eb781a8113b1af1d814e2f060f6408a2c990db291bc5108a1345c1e", "key": "bitcoin:POLIS", "maintainer": "Cronos ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 1000, "name": "Polis", "segwit": false, "shortcut": "POLIS", "signed_message_header": "Polis Signed Message:\n", "slip44": 1997, "support": {"connect": false, "trezor1": "soon", "trezor2": "2.1.1", "webwallet": false}, "uri_prefix": "polis", "website": "https://www.polispay.org", "xprv_magic": 65165637, "xpub_magic": 65166718, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 23, "address_type_p2sh": 83, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Primecoin", "coin_name": "Primecoin", "coin_shortcut": "XPM", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/primecoin/primecoin", "hash_genesis_block": "963d17ba4dc753138078a2f56afb3af9674e2546822badff26837db9a0152106", "key": "bitcoin:XPM", "maintainer": "James Skrowvedeht ", "max_address_length": 35, "maxfee_kb": 1000000, "min_address_length": 26, "minfee_kb": 1000, "name": "Primecoin", "segwit": false, "shortcut": "XPM", "signed_message_header": "Primecoin Signed Message:\n", "slip44": 24, "support": {"connect": true, "trezor1": "1.8.0", "trezor2": "2.0.11", "webwallet": false}, "uri_prefix": "primecoin", "website": "https://primecoin.io", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 58, "address_type_p2sh": 50, "bech32_prefix": "qc", "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 128, "cashaddr_prefix": null, "coin_label": "Qtum", "coin_name": "Qtum", "coin_shortcut": "QTUM", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 500, "High": 2000, "Low": 410, "Normal": 600}, "duplicate": true, "dust_limit": 218400, "force_bip143": false, "fork_id": null, "github": "https://github.com/qtumproject/qtum", "hash_genesis_block": "000075aef83cf2853580f8ae8ce6f8c3096cfa21d98334d6e3f95e5582ed986c", "key": "bitcoin:QTUM", "maintainer": "CodeFace ", "max_address_length": 34, "maxfee_kb": 40000000, "min_address_length": 27, "minfee_kb": 400000, "name": "Qtum", "segwit": true, "shortcut": "QTUM", "signed_message_header": "Qtum Signed Message:\n", "slip44": 2301, "support": {"connect": false, "trezor1": "1.8.1", "trezor2": "2.1.1", "webwallet": false}, "uri_prefix": "qtum", "website": "https://qtum.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 120, "address_type_p2sh": 110, "bech32_prefix": "tq", "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 128, "cashaddr_prefix": null, "coin_label": "Qtum Testnet", "coin_name": "Qtum Testnet", "coin_shortcut": "tQTUM", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 500, "High": 2000, "Low": 410, "Normal": 600}, "dust_limit": 218400, "force_bip143": false, "fork_id": null, "github": "https://github.com/qtumproject/qtum", "hash_genesis_block": "0000e803ee215c0684ca0d2f9220594d3f828617972aad66feb2ba51f5e14222", "key": "bitcoin:tQTUM", "maintainer": "CodeFace ", "max_address_length": 34, "maxfee_kb": 40000000, "min_address_length": 27, "minfee_kb": 400000, "name": "Qtum Testnet", "segwit": true, "shortcut": "tQTUM", "signed_message_header": "Qtum Signed Message:\n", "slip44": 1, "support": {"connect": false, "trezor1": "1.8.1", "trezor2": "2.1.1", "webwallet": false}, "uri_prefix": "qtum", "website": "https://qtum.org", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": 73342198, "xpub_magic_segwit_p2sh": 71979618}, {"address_type": 60, "address_type_p2sh": 122, "bech32_prefix": null, "bip115": false, "bitcore": ["https://ravencoin.network"], "blockbook": ["https://blockbook.ravencoin.org"], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Ravencoin", "coin_name": "Ravencoin", "coin_shortcut": "RVN", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Low": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/RavenProject/Ravencoin", "hash_genesis_block": "0000006b444bc2f2ffe627be9d9e7e7a0730000870ef6eb6da46c8eae389df90", "key": "bitcoin:RVN", "maintainer": "Scotty ", "max_address_length": 34, "maxfee_kb": 2000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Ravencoin", "segwit": false, "shortcut": "RVN", "signed_message_header": "Raven Signed Message:\n", "slip44": 175, "support": {"connect": true, "trezor1": "1.7.2", "trezor2": "2.0.10", "webwallet": true}, "uri_prefix": "raven", "website": "https://ravencoin.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 111, "address_type_p2sh": 196, "bech32_prefix": "bcrt", "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Regtest", "coin_name": "Regtest", "coin_shortcut": "REGTEST", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/bitcoin/bitcoin", "hash_genesis_block": "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206", "key": "bitcoin:REGTEST", "maintainer": "Thomas Kerin ", "max_address_length": 34, "maxfee_kb": 10000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Regtest", "segwit": true, "shortcut": "REGTEST", "signed_message_header": "Bitcoin Signed Message:\n", "slip44": 1, "support": {"connect": false, "trezor1": "1.8.2", "trezor2": "2.1.1", "webwallet": false}, "uri_prefix": "bitcoin", "website": "https://bitcoin.org", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": 73342198, "xpub_magic_segwit_p2sh": 71979618}, {"address_type": 25, "address_type_p2sh": 105, "bech32_prefix": null, "bip115": false, "bitcore": ["https://insight.ritocoin.org"], "blockbook": ["https://blockbook.ritocoin.org"], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Ritocoin", "coin_name": "Ritocoin", "coin_shortcut": "RITO", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Low": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/RitoProject", "hash_genesis_block": "00000075e344bdf1c0e433f453764b1830a7aa19b2a5213e707502a22b779c1b", "key": "bitcoin:RITO", "maintainer": "Scotty ", "max_address_length": 34, "maxfee_kb": 2000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Ritocoin", "segwit": false, "shortcut": "RITO", "signed_message_header": "Rito Signed Message:\n", "slip44": 19169, "support": {"connect": false, "trezor1": "1.8.2", "trezor2": "2.1.1", "webwallet": false}, "uri_prefix": "rito", "website": "https://ritocoin.org", "xprv_magic": 87326380, "xpub_magic": 87353290, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 63, "address_type_p2sh": 18, "bech32_prefix": null, "bip115": false, "bitcore": ["https://insight.smartcash.cc"], "blockbook": [], "blocktime_seconds": 55, "cashaddr_prefix": null, "coin_label": "SmartCash", "coin_name": "SmartCash", "coin_shortcut": "SMART", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1_smart", "decred": false, "default_fee_b": {"Economy": 10, "High": 200, "Low": 1, "Normal": 100}, "duplicate": true, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/SmartCash/Core-Smart", "hash_genesis_block": "000007acc6970b812948d14ea5a0a13db0fdd07d5047c7e69101fa8b361e05a4", "key": "bitcoin:SMART", "maintainer": "Leandro Reinaux ", "max_address_length": 34, "maxfee_kb": 1000000, "min_address_length": 27, "minfee_kb": 0, "name": "SmartCash", "segwit": false, "shortcut": "SMART", "signed_message_header": "SmartCash Signed Message:\n", "slip44": 224, "support": {"connect": false, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "smart", "website": "https://smartcash.cc", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 65, "address_type_p2sh": 21, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 55, "cashaddr_prefix": null, "coin_label": "SmartCash Testnet", "coin_name": "SmartCash Testnet", "coin_shortcut": "tSMART", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1_smart", "decred": false, "default_fee_b": {"Economy": 10, "High": 200, "Low": 1, "Normal": 100}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/SmartCash/Core-Smart", "hash_genesis_block": "0000027235b5679bcd28c90d03d4bf1a9ba4c07c4efcc1c87d6c68cce25e6e5d", "key": "bitcoin:tSMART", "maintainer": "Leandro Reinaux ", "max_address_length": 35, "maxfee_kb": 1000000, "min_address_length": 27, "minfee_kb": 0, "name": "SmartCash Testnet", "segwit": false, "shortcut": "tSMART", "signed_message_header": "SmartCash Signed Message:\n", "slip44": 224, "support": {"connect": false, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": false}, "uri_prefix": "testsmart", "website": "https://smartcash.cc", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 76, "address_type_p2sh": 16, "bech32_prefix": "xc", "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 60, "cashaddr_prefix": null, "coin_label": "Stakenet", "coin_name": "Stakenet", "coin_shortcut": "XSN", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 70, "High": 200, "Low": 10, "Normal": 140}, "dust_limit": 1000, "force_bip143": false, "fork_id": null, "github": "https://github.com/X9Developers/XSN", "hash_genesis_block": "00000c822abdbb23e28f79a49d29b41429737c6c7e15df40d1b1f1b35907ae34", "key": "bitcoin:XSN", "maintainer": "Alexis Hernandez ", "max_address_length": 47, "maxfee_kb": 2000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Stakenet", "segwit": true, "shortcut": "XSN", "signed_message_header": "DarkCoin Signed Message:\n", "slip44": 199, "support": {"connect": true, "trezor1": "1.8.0", "trezor2": "2.0.11", "webwallet": false}, "uri_prefix": "stakenet", "website": "https://stakenet.io", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 0, "address_type_p2sh": 5, "bech32_prefix": null, "bip115": false, "bitcore": ["https://insight.terracoin.io"], "blockbook": [], "blocktime_seconds": 120, "cashaddr_prefix": null, "coin_label": "Terracoin", "coin_name": "Terracoin", "coin_shortcut": "TRC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "duplicate": true, "dust_limit": 5460, "force_bip143": false, "fork_id": null, "github": "https://github.com/terracoin/terracoin", "hash_genesis_block": "00000000804bbc6a621a9dbb564ce469f492e1ccf2d70f8a6b241e26a277afa2", "key": "bitcoin:TRC", "maintainer": "The Terracoin Foundation ", "max_address_length": 34, "maxfee_kb": 100000, "min_address_length": 27, "minfee_kb": 10000, "name": "Terracoin", "segwit": false, "shortcut": "TRC", "signed_message_header": "DarkCoin Signed Message:\n", "slip44": 83, "support": {"connect": false, "trezor1": false, "trezor2": false, "webwallet": false}, "uri_prefix": "terracoin", "website": "https://terracoin.io", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 70, "address_type_p2sh": 50, "bech32_prefix": "vips", "bip115": false, "bitcore": ["https://insight.vipstarco.in"], "blockbook": ["https://vips.blockbook.japanesecoin-pool.work"], "blocktime_seconds": 120, "cashaddr_prefix": null, "coin_label": "VIPSTARCOIN", "coin_name": "VIPSTARCOIN", "coin_shortcut": "VIPS", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 500, "High": 2000, "Low": 410, "Normal": 600}, "dust_limit": 218400, "force_bip143": false, "fork_id": null, "github": "https://github.com/VIPSTARCOIN/VIPSTARCOIN", "hash_genesis_block": "0000d068e1d30f79fb64446137106be9c6ee69a6a722295c131506b1ee09b77c", "key": "bitcoin:VIPS", "maintainer": "y-chan ", "max_address_length": 36, "maxfee_kb": 40000000, "min_address_length": 27, "minfee_kb": 400000, "name": "VIPSTARCOIN", "segwit": true, "shortcut": "VIPS", "signed_message_header": "VIPSTARCOIN Signed Message:\n", "slip44": 1919, "support": {"connect": false, "trezor1": "1.8.2", "trezor2": "2.1.1", "webwallet": false}, "uri_prefix": "vipstarcoin", "website": "https://vipstarcoin.jp", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 71, "address_type_p2sh": 5, "bech32_prefix": "vtc", "bip115": false, "bitcore": [], "blockbook": ["https://vtc1.trezor.io", "https://vtc2.trezor.io", "https://vtc3.trezor.io", "https://vtc4.trezor.io", "https://vtc5.trezor.io"], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Vertcoin", "coin_name": "Vertcoin", "coin_shortcut": "VTC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 1000}, "dust_limit": 54600, "force_bip143": false, "fork_id": null, "github": "https://github.com/vertcoin-project/vertcoin-core", "hash_genesis_block": "4d96a915f49d40b1e5c2844d1ee2dccb90013a990ccea12c492d22110489f0c4", "key": "bitcoin:VTC", "maintainer": "Jochen Hoenicke ", "max_address_length": 34, "maxfee_kb": 40000000, "min_address_length": 27, "minfee_kb": 100000, "name": "Vertcoin", "segwit": true, "shortcut": "VTC", "signed_message_header": "Vertcoin Signed Message:\n", "slip44": 28, "support": {"connect": true, "trezor1": "1.6.1", "trezor2": "2.0.5", "webwallet": true}, "uri_prefix": "vertcoin", "website": "https://vertcoin.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 71, "address_type_p2sh": 33, "bech32_prefix": "via", "bip115": false, "bitcore": ["https://explorer.viacoin.org"], "blockbook": [], "blocktime_seconds": 24, "cashaddr_prefix": null, "coin_label": "Viacoin", "coin_name": "Viacoin", "coin_shortcut": "VIA", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 7000, "High": 20000, "Low": 1000, "Normal": 14000}, "dust_limit": 54600, "force_bip143": false, "fork_id": null, "github": "https://github.com/viacoin", "hash_genesis_block": "4e9b54001f9976049830128ec0331515eaabe35a70970d79971da1539a400ba1", "key": "bitcoin:VIA", "maintainer": "romanornr ", "max_address_length": 34, "maxfee_kb": 40000000, "min_address_length": 27, "minfee_kb": 1000, "name": "Viacoin", "segwit": true, "shortcut": "VIA", "signed_message_header": "Viacoin Signed Message:\n", "slip44": 14, "support": {"connect": true, "trezor1": "1.6.2", "trezor2": "2.0.7", "webwallet": true}, "uri_prefix": "viacoin", "website": "https://viacoin.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": 78792518, "xpub_magic_segwit_p2sh": 77429938}, {"address_type": 7352, "address_type_p2sh": 7357, "bech32_prefix": null, "bip115": false, "bitcore": ["https://explorer.zcl.zeltrez.io"], "blockbook": [], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "ZClassic", "coin_name": "ZClassic", "coin_shortcut": "ZCL", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/ZclassicCommunity", "hash_genesis_block": "0007104ccda289427919efc39dc9e4d499804b7bebc22df55f8b834301260602", "key": "bitcoin:ZCL", "maintainer": "James Skrowvedeht ", "max_address_length": 95, "maxfee_kb": 1000000, "min_address_length": 35, "minfee_kb": 1000, "name": "ZClassic", "segwit": false, "shortcut": "ZCL", "signed_message_header": "Zcash Signed Message:\n", "slip44": 147, "support": {"connect": true, "trezor1": "1.8.0", "trezor2": "2.0.11", "webwallet": false}, "uri_prefix": "zclassic", "website": "https://zclassic.org", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 7352, "address_type_p2sh": 7357, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://zec1.trezor.io", "https://zec2.trezor.io", "https://zec3.trezor.io", "https://zec4.trezor.io", "https://zec5.trezor.io"], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Zcash", "coin_name": "Zcash", "coin_shortcut": "ZEC", "consensus_branch_id": {"1": 0, "2": 0, "3": 1537743641, "4": 1991772603}, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/zcash/zcash", "hash_genesis_block": "00040fe8ec8471911baa1db1266ea15dd06b4a8a5c453883c000b031973dce08", "key": "bitcoin:ZEC", "maintainer": "Pavol Rusnak ", "max_address_length": 95, "maxfee_kb": 1000000, "min_address_length": 35, "minfee_kb": 1000, "name": "Zcash", "segwit": false, "shortcut": "ZEC", "signed_message_header": "Zcash Signed Message:\n", "slip44": 133, "support": {"connect": true, "trezor1": "1.7.1", "trezor2": "2.0.8", "webwallet": true}, "uri_prefix": "zcash", "website": "https://z.cash", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 7461, "address_type_p2sh": 7354, "bech32_prefix": null, "bip115": false, "bitcore": ["https://explorer.testnet.z.cash"], "blockbook": [], "blocktime_seconds": 150, "cashaddr_prefix": null, "coin_label": "Zcash Testnet", "coin_name": "Zcash Testnet", "coin_shortcut": "TAZ", "consensus_branch_id": {"1": 0, "2": 0, "3": 1537743641, "4": 1991772603}, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/zcash/zcash", "hash_genesis_block": "05a60a92d99d85997cce3b87616c089f6124d7342af37106edc76126334a2c38", "key": "bitcoin:TAZ", "maintainer": "Pavol Rusnak ", "max_address_length": 95, "maxfee_kb": 10000000, "min_address_length": 35, "minfee_kb": 1000, "name": "Zcash Testnet", "segwit": false, "shortcut": "TAZ", "signed_message_header": "Zcash Signed Message:\n", "slip44": 1, "support": {"connect": true, "trezor1": "1.6.2", "trezor2": "2.0.7", "webwallet": true}, "uri_prefix": "zcash", "website": "https://z.cash", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 82, "address_type_p2sh": 7, "bech32_prefix": null, "bip115": false, "bitcore": ["https://insight.zcoin.io"], "blockbook": [], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Zcoin", "coin_name": "Zcoin", "coin_shortcut": "XZC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 10, "High": 200, "Low": 1, "Normal": 100}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/zcoinofficial/zcoin", "hash_genesis_block": "4381deb85b1b2c9843c222944b616d997516dcbd6a964e1eaf0def0830695233", "key": "bitcoin:XZC", "maintainer": "Yura Pakhuchiy ", "max_address_length": 34, "maxfee_kb": 1000000, "min_address_length": 27, "minfee_kb": 0, "name": "Zcoin", "segwit": false, "shortcut": "XZC", "signed_message_header": "Zcoin Signed Message:\n", "slip44": 136, "support": {"connect": true, "trezor1": "1.6.2", "trezor2": "2.0.7", "webwallet": true}, "uri_prefix": "zcoin", "website": "https://zcoin.io", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 65, "address_type_p2sh": 178, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": [], "blocktime_seconds": 600, "cashaddr_prefix": null, "coin_label": "Zcoin Testnet", "coin_name": "Zcoin Testnet", "coin_shortcut": "tXZC", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Economy": 10, "High": 200, "Low": 1, "Normal": 100}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/zcoinofficial/zcoin", "hash_genesis_block": "7ac038c193c2158c428c59f9ae0c02a07115141c6e9dc244ae96132e99b4e642", "key": "bitcoin:tXZC", "maintainer": "Yura Pakhuchiy ", "max_address_length": 35, "maxfee_kb": 1000000, "min_address_length": 27, "minfee_kb": 0, "name": "Zcoin Testnet", "segwit": false, "shortcut": "tXZC", "signed_message_header": "Zcoin Signed Message:\n", "slip44": 1, "support": {"connect": true, "trezor1": "1.6.2", "trezor2": "2.0.7", "webwallet": false}, "uri_prefix": "testzcoin", "website": "https://zcoin.io", "xprv_magic": 70615956, "xpub_magic": 70617039, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}, {"address_type": 7352, "address_type_p2sh": 7357, "bech32_prefix": null, "bip115": false, "bitcore": [], "blockbook": ["https://blockbook.zel.network"], "blocktime_seconds": 120, "cashaddr_prefix": null, "coin_label": "Zel", "coin_name": "ZelCash", "coin_shortcut": "ZEL", "consensus_branch_id": null, "cooldown": 100, "curve_name": "secp256k1", "decred": false, "default_fee_b": {"Normal": 10}, "dust_limit": 546, "force_bip143": false, "fork_id": null, "github": "https://github.com/zelcash", "hash_genesis_block": "00052461a5006c2e3b74ce48992a08695607912d5604c3eb8da25749b0900444", "key": "bitcoin:ZEL", "maintainer": "Cabecinha84 ", "max_address_length": 95, "maxfee_kb": 1000000, "min_address_length": 35, "minfee_kb": 1000, "name": "Zel", "segwit": false, "shortcut": "ZEL", "signed_message_header": "Zcash Signed Message:\n", "slip44": 19167, "support": {"connect": false, "trezor1": null, "trezor2": null, "webwallet": false}, "uri_prefix": "zelcash", "website": "https://zel.network", "xprv_magic": 76066276, "xpub_magic": 76067358, "xpub_magic_segwit_native": null, "xpub_magic_segwit_p2sh": null}] diff --git a/python/trezorlib/messages/ResetDevice.py b/python/trezorlib/messages/ResetDevice.py index 719b8106cb..87bea0c274 100644 --- a/python/trezorlib/messages/ResetDevice.py +++ b/python/trezorlib/messages/ResetDevice.py @@ -17,6 +17,7 @@ class ResetDevice(p.MessageType): u2f_counter: int = None, skip_backup: bool = None, no_backup: bool = None, + slip39: bool = None, ) -> None: self.display_random = display_random self.strength = strength @@ -27,6 +28,7 @@ class ResetDevice(p.MessageType): self.u2f_counter = u2f_counter self.skip_backup = skip_backup self.no_backup = no_backup + self.slip39 = slip39 @classmethod def get_fields(cls): @@ -40,4 +42,5 @@ class ResetDevice(p.MessageType): 7: ('u2f_counter', p.UVarintType, 0), 8: ('skip_backup', p.BoolType, 0), 9: ('no_backup', p.BoolType, 0), + 10: ('slip39', p.BoolType, 0), }