From dcb15f77c3aa39e272619357380ed289560a66a6 Mon Sep 17 00:00:00 2001 From: Jan Pochyla Date: Tue, 3 Jul 2018 16:20:58 +0200 Subject: [PATCH] src: run black --- src/apps/common/address_type.py | 36 +- src/apps/common/cache.py | 2 +- src/apps/common/coininfo.py | 4 +- src/apps/common/coins.py | 4 +- src/apps/common/confirm.py | 6 +- src/apps/common/display_address.py | 16 +- src/apps/common/request_passphrase.py | 29 +- src/apps/common/request_pin.py | 13 +- src/apps/common/seed.py | 16 +- src/apps/common/signverify.py | 1 - src/apps/common/storage.py | 45 +- src/apps/debug/__init__.py | 13 +- src/apps/ethereum/__init__.py | 4 + src/apps/ethereum/get_address.py | 10 +- src/apps/ethereum/layout.py | 28 +- src/apps/ethereum/networks.py | 12 +- src/apps/ethereum/sign_message.py | 4 +- src/apps/ethereum/sign_tx.py | 50 +- src/apps/ethereum/tokens.py | 5012 ++++++++++++++--- src/apps/ethereum/verify_message.py | 12 +- src/apps/fido_u2f/__init__.py | 232 +- src/apps/fido_u2f/knownapps.py | 36 +- src/apps/homescreen/__init__.py | 24 +- src/apps/homescreen/homescreen.py | 18 +- src/apps/lisk/__init__.py | 5 + src/apps/lisk/helpers.py | 14 +- src/apps/lisk/layout.py | 26 +- src/apps/lisk/sign_message.py | 4 +- src/apps/lisk/sign_tx.py | 63 +- src/apps/lisk/verify_message.py | 4 +- src/apps/management/__init__.py | 9 + src/apps/management/apply_flags.py | 2 +- src/apps/management/apply_settings.py | 53 +- src/apps/management/backup_device.py | 6 +- src/apps/management/change_pin.py | 48 +- src/apps/management/load_device.py | 22 +- src/apps/management/recovery_device.py | 34 +- src/apps/management/reset_device.py | 90 +- src/apps/management/set_u2f_counter.py | 10 +- src/apps/management/wipe_device.py | 15 +- src/apps/nem/__init__.py | 2 + src/apps/nem/get_address.py | 8 +- src/apps/nem/helpers.py | 10 +- src/apps/nem/layout.py | 20 +- src/apps/nem/mosaic/__init__.py | 8 +- src/apps/nem/mosaic/layout.py | 96 +- src/apps/nem/mosaic/serialize.py | 59 +- src/apps/nem/multisig/__init__.py | 16 +- src/apps/nem/multisig/layout.py | 26 +- src/apps/nem/multisig/serialize.py | 30 +- src/apps/nem/namespace/__init__.py | 7 +- src/apps/nem/namespace/layout.py | 27 +- src/apps/nem/namespace/serialize.py | 10 +- src/apps/nem/signing.py | 18 +- src/apps/nem/transfer/__init__.py | 8 +- src/apps/nem/transfer/layout.py | 104 +- src/apps/nem/transfer/serialize.py | 34 +- src/apps/nem/validators.py | 191 +- src/apps/nem/writers.py | 10 +- src/apps/wallet/__init__.py | 9 + src/apps/wallet/cipher_key_value.py | 10 +- src/apps/wallet/ecdh.py | 33 +- src/apps/wallet/get_address.py | 9 +- src/apps/wallet/get_entropy.py | 6 +- src/apps/wallet/get_public_key.py | 14 +- src/apps/wallet/sign_identity.py | 90 +- src/apps/wallet/sign_message.py | 6 +- src/apps/wallet/sign_tx/addresses.py | 73 +- src/apps/wallet/sign_tx/helpers.py | 16 +- src/apps/wallet/sign_tx/layout.py | 29 +- src/apps/wallet/sign_tx/multisig.py | 10 +- src/apps/wallet/sign_tx/overwinter_zip143.py | 54 +- src/apps/wallet/sign_tx/progress.py | 2 +- src/apps/wallet/sign_tx/scripts.py | 4 +- src/apps/wallet/sign_tx/segwit_bip143.py | 48 +- src/apps/wallet/sign_tx/signing.py | 232 +- .../wallet/sign_tx/tx_weight_calculator.py | 37 +- src/apps/wallet/sign_tx/writers.py | 2 +- src/apps/wallet/verify_message.py | 16 +- src/boot.py | 14 +- src/main.py | 2 + src/protobuf.py | 10 +- src/trezor/crypto/aes.py | 40 +- src/trezor/crypto/base32.py | 51 +- src/trezor/crypto/base58.py | 32 +- src/trezor/crypto/bech32.py | 13 +- src/trezor/crypto/cashaddr.py | 8 +- src/trezor/crypto/der.py | 11 +- src/trezor/crypto/hmac.py | 14 +- src/trezor/crypto/rlp.py | 9 +- src/trezor/log.py | 21 +- src/trezor/loop.py | 42 +- src/trezor/pin.py | 30 +- src/trezor/res/__init__.py | 8 +- src/trezor/ui/button.py | 45 +- src/trezor/ui/confirm.py | 36 +- src/trezor/ui/container.py | 1 - src/trezor/ui/entry_select.py | 5 +- src/trezor/ui/loader.py | 23 +- src/trezor/ui/mnemonic.py | 34 +- src/trezor/ui/passphrase.py | 29 +- src/trezor/ui/pin.py | 8 +- src/trezor/ui/qr.py | 1 - src/trezor/ui/scroll.py | 9 +- src/trezor/ui/style.py | 380 +- src/trezor/ui/swipe.py | 31 +- src/trezor/ui/text.py | 42 +- src/trezor/ui/word_select.py | 16 +- src/trezor/utils.py | 25 +- src/trezor/wire/__init__.py | 40 +- src/trezor/wire/codec_v1.py | 41 +- 111 files changed, 6230 insertions(+), 2257 deletions(-) diff --git a/src/apps/common/address_type.py b/src/apps/common/address_type.py index ff57d8e47..43737d1e9 100644 --- a/src/apps/common/address_type.py +++ b/src/apps/common/address_type.py @@ -17,7 +17,14 @@ def addrtype_bytes(address_type: int): if address_type <= 0xFFFFFF: return bytes([(address_type >> 16), (address_type >> 8), (address_type & 0xFF)]) # else - return bytes([(address_type >> 24), (address_type >> 16), (address_type >> 8), (address_type & 0xFF)]) + return bytes( + [ + (address_type >> 24), + (address_type >> 16), + (address_type >> 8), + (address_type & 0xFF), + ] + ) def check(address_type, raw_address): @@ -26,25 +33,36 @@ def check(address_type, raw_address): if address_type <= 0xFFFF: return address_type == (raw_address[0] << 8) | raw_address[1] if address_type <= 0xFFFFFF: - return address_type == (raw_address[0] << 16) | (raw_address[1] << 8) | raw_address[2] + return ( + address_type + == (raw_address[0] << 16) | (raw_address[1] << 8) | raw_address[2] + ) # else - return address_type == (raw_address[0] << 24) | (raw_address[1] << 16) | (raw_address[2] << 8) | raw_address[3] + return ( + address_type + == (raw_address[0] << 24) + | (raw_address[1] << 16) + | (raw_address[2] << 8) + | raw_address[3] + ) def strip(address_type, raw_address): if not check(address_type, raw_address): - raise ValueError('Invalid address') + raise ValueError("Invalid address") l = length(address_type) return raw_address[l:] def split(coin, raw_address): - for f in ('address_type', - 'address_type_p2sh', - 'address_type_p2wpkh', - 'address_type_p2wsh'): + for f in ( + "address_type", + "address_type_p2sh", + "address_type_p2wpkh", + "address_type_p2wsh", + ): at = getattr(coin, f) if at is not None and check(at, raw_address): l = length(at) return raw_address[:l], raw_address[l:] - raise ValueError('Invalid address') + raise ValueError("Invalid address") diff --git a/src/apps/common/cache.py b/src/apps/common/cache.py index b58684bf7..ee1ae4907 100644 --- a/src/apps/common/cache.py +++ b/src/apps/common/cache.py @@ -53,6 +53,6 @@ def set_passphrase(passphrase): def clear(skip_passphrase: bool = False): set_seed(None) if skip_passphrase: - set_passphrase('') + set_passphrase("") else: set_passphrase(None) diff --git a/src/apps/common/coininfo.py b/src/apps/common/coininfo.py index 4df19faa5..64bed3f4b 100644 --- a/src/apps/common/coininfo.py +++ b/src/apps/common/coininfo.py @@ -1,7 +1,7 @@ from trezor.crypto.base58 import groestl512d_32, sha256d_32 -class CoinInfo: +class CoinInfo: def __init__( self, coin_name: str, @@ -37,7 +37,7 @@ class CoinInfo: self.version_group_id = version_group_id self.bip115 = bip115 self.curve_name = curve_name - if curve_name == 'secp256k1-groestl': + if curve_name == "secp256k1-groestl": self.b58_hash = groestl512d_32 self.sign_hash_double = False else: diff --git a/src/apps/common/coins.py b/src/apps/common/coins.py index 7810cf990..b4ed50bac 100644 --- a/src/apps/common/coins.py +++ b/src/apps/common/coins.py @@ -19,11 +19,11 @@ def by_address_type(address_type): for c in COINS: if c.address_type == address_type: return c - raise ValueError('Unknown coin address type %d' % address_type) + raise ValueError("Unknown coin address type %d" % address_type) def by_slip44(slip44): for c in COINS: if c.slip44 == slip44: return c - raise ValueError('Unknown coin slip44 index %d' % slip44) + raise ValueError("Unknown coin slip44 index %d" % slip44) diff --git a/src/apps/common/confirm.py b/src/apps/common/confirm.py index a37fefb68..3f057447d 100644 --- a/src/apps/common/confirm.py +++ b/src/apps/common/confirm.py @@ -21,7 +21,7 @@ async def hold_to_confirm(ctx, content, code=None, *args, **kwargs): code = ButtonRequestType.Other await ctx.call(ButtonRequest(code=code), MessageType.ButtonAck) - dialog = HoldToConfirmDialog(content, 'Hold to confirm', *args, **kwargs) + dialog = HoldToConfirmDialog(content, "Hold to confirm", *args, **kwargs) return await ctx.wait(dialog) == CONFIRMED @@ -29,10 +29,10 @@ async def hold_to_confirm(ctx, content, code=None, *args, **kwargs): async def require_confirm(*args, **kwargs): confirmed = await confirm(*args, **kwargs) if not confirmed: - raise wire.ActionCancelled('Cancelled') + raise wire.ActionCancelled("Cancelled") async def require_hold_to_confirm(*args, **kwargs): confirmed = await hold_to_confirm(*args, **kwargs) if not confirmed: - raise wire.ActionCancelled('Cancelled') + raise wire.ActionCancelled("Cancelled") diff --git a/src/apps/common/display_address.py b/src/apps/common/display_address.py index 17691fcaf..195e8a37b 100644 --- a/src/apps/common/display_address.py +++ b/src/apps/common/display_address.py @@ -12,14 +12,11 @@ from apps.common.confirm import confirm async def show_address(ctx, address: str): lines = split_address(address) - text = Text('Confirm address', ui.ICON_RECEIVE, icon_color=ui.GREEN) + text = Text("Confirm address", ui.ICON_RECEIVE, icon_color=ui.GREEN) text.mono(*lines) return await confirm( - ctx, - text, - code=ButtonRequestType.Address, - cancel='QR', - cancel_style=ui.BTN_KEY) + ctx, text, code=ButtonRequestType.Address, cancel="QR", cancel_style=ui.BTN_KEY + ) async def show_qr(ctx, address: str): @@ -28,14 +25,15 @@ async def show_qr(ctx, address: str): qr_coef = const(4) qr = Qr(address, (qr_x, qr_y), qr_coef) - text = Text('Confirm address', ui.ICON_RECEIVE, icon_color=ui.GREEN) + text = Text("Confirm address", ui.ICON_RECEIVE, icon_color=ui.GREEN) content = Container(qr, text) return await confirm( ctx, content, code=ButtonRequestType.Address, - cancel='Address', - cancel_style=ui.BTN_KEY) + cancel="Address", + cancel_style=ui.BTN_KEY, + ) def split_address(address: str): diff --git a/src/apps/common/request_passphrase.py b/src/apps/common/request_passphrase.py index 5faec3229..08e72c9a9 100644 --- a/src/apps/common/request_passphrase.py +++ b/src/apps/common/request_passphrase.py @@ -13,16 +13,17 @@ from apps.common.cache import get_state @ui.layout async def request_passphrase_entry(ctx): - text = Text('Enter passphrase', ui.ICON_CONFIG) - text.normal('Where to enter your', 'passphrase?') + text = Text("Enter passphrase", ui.ICON_CONFIG) + text.normal("Where to enter your", "passphrase?") text.render() ack = await ctx.call( ButtonRequest(code=ButtonRequestType.PassphraseType), MessageType.ButtonAck, - MessageType.Cancel) + MessageType.Cancel, + ) if ack.MESSAGE_WIRE_TYPE == MessageType.Cancel: - raise wire.ActionCancelled('Passphrase cancelled') + raise wire.ActionCancelled("Passphrase cancelled") selector = EntrySelector(text) return await ctx.wait(selector) @@ -31,28 +32,30 @@ async def request_passphrase_entry(ctx): @ui.layout async def request_passphrase_ack(ctx, on_device): if not on_device: - text = Text('Passphrase entry', ui.ICON_CONFIG) - text.normal('Please, type passphrase', 'on connected host.') + text = Text("Passphrase entry", ui.ICON_CONFIG) + text.normal("Please, type passphrase", "on connected host.") text.render() req = PassphraseRequest(on_device=on_device) ack = await ctx.call(req, MessageType.PassphraseAck, MessageType.Cancel) if ack.MESSAGE_WIRE_TYPE == MessageType.Cancel: - raise wire.ActionCancelled('Passphrase cancelled') + raise wire.ActionCancelled("Passphrase cancelled") if on_device: if ack.passphrase is not None: - raise wire.ProcessError('Passphrase provided when it should not be') - keyboard = PassphraseKeyboard('Enter passphrase') + raise wire.ProcessError("Passphrase provided when it should not be") + keyboard = PassphraseKeyboard("Enter passphrase") passphrase = await ctx.wait(keyboard) if passphrase == CANCELLED: - raise wire.ActionCancelled('Passphrase cancelled') + raise wire.ActionCancelled("Passphrase cancelled") else: if ack.passphrase is None: - raise wire.ProcessError('Passphrase not provided') + raise wire.ProcessError("Passphrase not provided") passphrase = ack.passphrase - req = PassphraseStateRequest(state=get_state(prev_state=ack.state, passphrase=passphrase)) + req = PassphraseStateRequest( + state=get_state(prev_state=ack.state, passphrase=passphrase) + ) ack = await ctx.call(req, MessageType.PassphraseStateAck, MessageType.Cancel) return passphrase @@ -71,4 +74,4 @@ async def protect_by_passphrase(ctx): if storage.has_passphrase(): return await request_passphrase(ctx) else: - return '' + return "" diff --git a/src/apps/common/request_pin.py b/src/apps/common/request_pin.py index 4455c02de..1c9d0e04f 100644 --- a/src/apps/common/request_pin.py +++ b/src/apps/common/request_pin.py @@ -11,32 +11,31 @@ class PinCancelled(Exception): @ui.layout -async def request_pin(label=None, cancellable: bool=True) -> str: - +async def request_pin(label=None, cancellable: bool = True) -> str: def onchange(): c = dialog.cancel if matrix.pin: back = res.load(ui.ICON_BACK) if c.content is not back: - c.normal_style = ui.BTN_CLEAR['normal'] + c.normal_style = ui.BTN_CLEAR["normal"] c.content = back c.enable() c.taint() else: lock = res.load(ui.ICON_LOCK) if not cancellable and c.content: - c.content = '' + c.content = "" c.disable() c.taint() elif c.content is not lock: - c.normal_style = ui.BTN_CANCEL['normal'] + c.normal_style = ui.BTN_CANCEL["normal"] c.content = lock c.enable() c.taint() c.render() if label is None: - label = 'Enter your PIN' + label = "Enter your PIN" matrix = PinMatrix(label) matrix.onchange = onchange dialog = ConfirmDialog(matrix) @@ -54,7 +53,7 @@ async def request_pin(label=None, cancellable: bool=True) -> str: if result == CONFIRMED: return matrix.pin elif matrix.pin: # reset - matrix.change('') + matrix.change("") continue else: # cancel raise PinCancelled() diff --git a/src/apps/common/seed.py b/src/apps/common/seed.py index f774f65b9..1bb22f593 100644 --- a/src/apps/common/seed.py +++ b/src/apps/common/seed.py @@ -4,10 +4,12 @@ from trezor.crypto import bip32, bip39 from apps.common import cache, storage from apps.common.request_passphrase import protect_by_passphrase -_DEFAULT_CURVE = 'secp256k1' +_DEFAULT_CURVE = "secp256k1" -async def derive_node(ctx: wire.Context, path: list, curve_name: str = _DEFAULT_CURVE) -> bip32.HDNode: +async def derive_node( + ctx: wire.Context, path: list, curve_name: str = _DEFAULT_CURVE +) -> bip32.HDNode: seed = await _get_cached_seed(ctx) node = bip32.from_seed(seed, curve_name) node.derive_path(path) @@ -16,7 +18,7 @@ async def derive_node(ctx: wire.Context, path: list, curve_name: str = _DEFAULT_ async def _get_cached_seed(ctx: wire.Context) -> bytes: if not storage.is_initialized(): - raise wire.ProcessError('Device is not initialized') + raise wire.ProcessError("Device is not initialized") if cache.get_seed() is None: passphrase = await _get_cached_passphrase(ctx) seed = bip39.seed(storage.get_mnemonic(), passphrase) @@ -31,11 +33,13 @@ async def _get_cached_passphrase(ctx: wire.Context) -> str: return cache.get_passphrase() -def derive_node_without_passphrase(path: list, curve_name: str = _DEFAULT_CURVE) -> bip32.HDNode: +def derive_node_without_passphrase( + path: list, curve_name: str = _DEFAULT_CURVE +) -> bip32.HDNode: if not storage.is_initialized(): - raise Exception('Device is not initialized') + raise Exception("Device is not initialized") - seed = bip39.seed(storage.get_mnemonic(), '') + seed = bip39.seed(storage.get_mnemonic(), "") node = bip32.from_seed(seed, curve_name) node.derive_path(path) return node diff --git a/src/apps/common/signverify.py b/src/apps/common/signverify.py index 2db3e5f75..231ca4786 100644 --- a/src/apps/common/signverify.py +++ b/src/apps/common/signverify.py @@ -21,7 +21,6 @@ def message_digest(coin, message): def split_message(message): - def measure(s): return ui.display.text_width(s, ui.NORMAL) diff --git a/src/apps/common/storage.py b/src/apps/common/storage.py index f27b088b3..6295e06e3 100644 --- a/src/apps/common/storage.py +++ b/src/apps/common/storage.py @@ -8,7 +8,7 @@ from apps.common import cache HOMESCREEN_MAXSIZE = 16384 -_STORAGE_VERSION = b'\x01' +_STORAGE_VERSION = b"\x01" # fmt: off _APP = const(0x01) # app namespace @@ -64,9 +64,9 @@ def load_mnemonic(mnemonic: str, needs_backup: bool) -> None: config.set(_APP, _MNEMONIC, mnemonic.encode()) config.set(_APP, _VERSION, _STORAGE_VERSION) if needs_backup: - config.set(_APP, _NEEDS_BACKUP, b'\x01') + config.set(_APP, _NEEDS_BACKUP, b"\x01") else: - config.set(_APP, _NEEDS_BACKUP, b'') + config.set(_APP, _NEEDS_BACKUP, b"") def needs_backup() -> bool: @@ -74,7 +74,7 @@ def needs_backup() -> bool: def set_backed_up() -> None: - config.set(_APP, _NEEDS_BACKUP, b'') + config.set(_APP, _NEEDS_BACKUP, b"") def unfinished_backup() -> bool: @@ -83,34 +83,39 @@ def unfinished_backup() -> bool: def set_unfinished_backup(state: bool) -> None: if state: - config.set(_APP, _UNFINISHED_BACKUP, b'\x01') + config.set(_APP, _UNFINISHED_BACKUP, b"\x01") else: - config.set(_APP, _UNFINISHED_BACKUP, b'') + config.set(_APP, _UNFINISHED_BACKUP, b"") def get_passphrase_source() -> int: b = config.get(_APP, _PASSPHRASE_SOURCE) - if b == b'\x01': + if b == b"\x01": return 1 - elif b == b'\x02': + elif b == b"\x02": return 2 else: return 0 -def load_settings(label: str=None, use_passphrase: bool=None, homescreen: bytes=None, passphrase_source: int=None) -> None: +def load_settings( + label: str = None, + use_passphrase: bool = None, + homescreen: bytes = None, + passphrase_source: int = None, +) -> None: if label is not None: config.set(_APP, _LABEL, label.encode(), True) # public if use_passphrase is True: - config.set(_APP, _USE_PASSPHRASE, b'\x01') + config.set(_APP, _USE_PASSPHRASE, b"\x01") if use_passphrase is False: - config.set(_APP, _USE_PASSPHRASE, b'') + config.set(_APP, _USE_PASSPHRASE, b"") if homescreen is not None: - if homescreen[:8] == b'TOIf\x90\x00\x90\x00': + if homescreen[:8] == b"TOIf\x90\x00\x90\x00": if len(homescreen) <= HOMESCREEN_MAXSIZE: config.set(_APP, _HOMESCREEN, homescreen, True) # public else: - config.set(_APP, _HOMESCREEN, b'', True) # public + config.set(_APP, _HOMESCREEN, b"", True) # public if passphrase_source is not None: if passphrase_source in [0, 1, 2]: config.set(_APP, _PASSPHRASE_SOURCE, bytes([passphrase_source])) @@ -121,7 +126,7 @@ def get_flags() -> int: if b is None: return 0 else: - return int.from_bytes(b, 'big') + return int.from_bytes(b, "big") def set_flags(flags: int) -> None: @@ -129,10 +134,10 @@ def set_flags(flags: int) -> None: if b is None: b = 0 else: - b = int.from_bytes(b, 'big') + b = int.from_bytes(b, "big") flags = (flags | b) & 0xFFFFFFFF if flags != b: - config.set(_APP, _FLAGS, flags.to_bytes(4, 'big')) + config.set(_APP, _FLAGS, flags.to_bytes(4, "big")) def get_autolock_delay_ms() -> int: @@ -140,13 +145,13 @@ def get_autolock_delay_ms() -> int: if b is None: return 10 * 60 * 1000 else: - return int.from_bytes(b, 'big') + return int.from_bytes(b, "big") def set_autolock_delay_ms(delay_ms: int) -> None: if delay_ms < 60 * 1000: delay_ms = 60 * 1000 - config.set(_APP, _AUTOLOCK_DELAY_MS, delay_ms.to_bytes(4, 'big')) + config.set(_APP, _AUTOLOCK_DELAY_MS, delay_ms.to_bytes(4, "big")) def next_u2f_counter() -> int: @@ -154,13 +159,13 @@ def next_u2f_counter() -> int: if b is None: b = 0 else: - b = int.from_bytes(b, 'big') + 1 + b = int.from_bytes(b, "big") + 1 set_u2f_counter(b) return b def set_u2f_counter(cntr: int): - config.set(_APP, _U2F_COUNTER, cntr.to_bytes(4, 'big')) + config.set(_APP, _U2F_COUNTER, cntr.to_bytes(4, "big")) def wipe(): diff --git a/src/apps/debug/__init__.py b/src/apps/debug/__init__.py index d3fa8fe67..90158ccbd 100644 --- a/src/apps/debug/__init__.py +++ b/src/apps/debug/__init__.py @@ -1,6 +1,7 @@ if not __debug__: from trezor.utils import halt - halt('debug mode inactive') + + halt("debug mode inactive") if __debug__: from trezor import loop @@ -33,12 +34,16 @@ if __debug__: m.reset_word_pos = reset_word_index m.reset_entropy = reset_internal_entropy if reset_current_words: - m.reset_word = ' '.join(reset_current_words) + m.reset_word = " ".join(reset_current_words) return m def boot(): # wipe storage when debug build is used storage.wipe() - register(MessageType.DebugLinkDecision, protobuf_workflow, dispatch_DebugLinkDecision) - register(MessageType.DebugLinkGetState, protobuf_workflow, dispatch_DebugLinkGetState) + register( + MessageType.DebugLinkDecision, protobuf_workflow, dispatch_DebugLinkDecision + ) + register( + MessageType.DebugLinkGetState, protobuf_workflow, dispatch_DebugLinkGetState + ) diff --git a/src/apps/ethereum/__init__.py b/src/apps/ethereum/__init__.py index 4229afbef..e862e4d70 100644 --- a/src/apps/ethereum/__init__.py +++ b/src/apps/ethereum/__init__.py @@ -9,21 +9,25 @@ from trezor.wire import protobuf_workflow, register def dispatch_EthereumGetAddress(*args, **kwargs): from .get_address import ethereum_get_address + return ethereum_get_address(*args, **kwargs) def dispatch_EthereumSignTx(*args, **kwargs): from .sign_tx import ethereum_sign_tx + return ethereum_sign_tx(*args, **kwargs) def dispatch_EthereumSignMessage(*args, **kwargs): from .sign_message import ethereum_sign_message + return ethereum_sign_message(*args, **kwargs) def dispatch_EthereumVerifyMessage(*args, **kwargs): from .verify_message import ethereum_verify_message + return ethereum_verify_message(*args, **kwargs) diff --git a/src/apps/ethereum/get_address.py b/src/apps/ethereum/get_address.py index 217b0e9d2..14bb33cdb 100644 --- a/src/apps/ethereum/get_address.py +++ b/src/apps/ethereum/get_address.py @@ -37,18 +37,18 @@ def _ethereum_address_hex(address, network=None): hx = hexlify(address).decode() - prefix = str(network.chain_id) + '0x' if rskip60 else '' + prefix = str(network.chain_id) + "0x" if rskip60 else "" hs = sha3_256(prefix + hx).digest(True) - h = '' + h = "" for i in range(20): l = hx[i * 2] - if hs[i] & 0x80 and l >= 'a' and l <= 'f': + if hs[i] & 0x80 and l >= "a" and l <= "f": l = l.upper() h += l l = hx[i * 2 + 1] - if hs[i] & 0x08 and l >= 'a' and l <= 'f': + if hs[i] & 0x08 and l >= "a" and l <= "f": l = l.upper() h += l - return '0x' + h + return "0x" + h diff --git a/src/apps/ethereum/layout.py b/src/apps/ethereum/layout.py index df58fba00..b96c7f4d1 100644 --- a/src/apps/ethereum/layout.py +++ b/src/apps/ethereum/layout.py @@ -14,21 +14,23 @@ async def require_confirm_tx(ctx, to, value, chain_id, token=None, tx_type=None) if to: to_str = _ethereum_address_hex(to, networks.by_chain_id(chain_id)) else: - to_str = 'new contract?' - text = Text('Confirm sending', ui.ICON_SEND, icon_color=ui.GREEN) + to_str = "new contract?" + text = Text("Confirm sending", ui.ICON_SEND, icon_color=ui.GREEN) text.bold(format_ethereum_amount(value, token, chain_id, tx_type)) - text.normal('to') + text.normal("to") text.mono(*split_address(to_str)) # we use SignTx, not ConfirmOutput, for compatibility with T1 await require_confirm(ctx, text, ButtonRequestType.SignTx) -async def require_confirm_fee(ctx, spending, gas_price, gas_limit, chain_id, token=None, tx_type=None): - text = Text('Confirm transaction', ui.ICON_SEND, icon_color=ui.GREEN) +async def require_confirm_fee( + ctx, spending, gas_price, gas_limit, chain_id, token=None, tx_type=None +): + text = Text("Confirm transaction", ui.ICON_SEND, icon_color=ui.GREEN) text.bold(format_ethereum_amount(spending, token, chain_id, tx_type)) - text.normal('Gas price:') + text.normal("Gas price:") text.bold(format_ethereum_amount(gas_price, None, chain_id, tx_type)) - text.normal('Maximum fee:') + text.normal("Maximum fee:") text.bold(format_ethereum_amount(gas_price * gas_limit, None, chain_id, tx_type)) await require_hold_to_confirm(ctx, text, ButtonRequestType.SignTx) @@ -40,9 +42,9 @@ def split_data(data): async def require_confirm_data(ctx, data, data_total): data_str = hexlify(data[:36]).decode() if data_total > 36: - data_str = data_str[:-2] + '..' - text = Text('Confirm data', ui.ICON_SEND, icon_color=ui.GREEN) - text.bold('Size: %d bytes' % data_total) + data_str = data_str[:-2] + ".." + text = Text("Confirm data", ui.ICON_SEND, icon_color=ui.GREEN) + text.bold("Size: %d bytes" % data_total) text.mono(*split_data(data_str)) # we use SignTx, not ConfirmOutput, for compatibility with T1 await require_confirm(ctx, text, ButtonRequestType.SignTx) @@ -55,7 +57,7 @@ def split_address(address): def format_ethereum_amount(value: int, token, chain_id: int, tx_type=None): if token: if token is tokens.UNKNOWN_TOKEN: - return 'Unknown token value' + return "Unknown token value" suffix = token[2] decimals = token[3] else: @@ -63,7 +65,7 @@ def format_ethereum_amount(value: int, token, chain_id: int, tx_type=None): decimals = 18 if value <= 1e9: - suffix = 'Wei ' + suffix + suffix = "Wei " + suffix decimals = 0 - return '%s %s' % (format_amount(value, decimals), suffix) + return "%s %s" % (format_amount(value, decimals), suffix) diff --git a/src/apps/ethereum/networks.py b/src/apps/ethereum/networks.py index 8981bba0a..dded083c7 100644 --- a/src/apps/ethereum/networks.py +++ b/src/apps/ethereum/networks.py @@ -1,9 +1,9 @@ def shortcut_by_chain_id(chain_id, tx_type=None): if tx_type in [1, 6] and chain_id in [1, 3]: - return 'WAN' + return "WAN" else: n = by_chain_id(chain_id) - return n.shortcut if n is not None else 'UNKN' + return n.shortcut if n is not None else "UNKN" def by_chain_id(chain_id): @@ -21,14 +21,8 @@ def by_slip44(slip44): class NetworkInfo: - def __init__( - self, - chain_id: int, - slip44: int, - shortcut: str, - name: str, - rskip60: bool + self, chain_id: int, slip44: int, shortcut: str, name: str, rskip60: bool ): self.chain_id = chain_id self.slip44 = slip44 diff --git a/src/apps/ethereum/sign_message.py b/src/apps/ethereum/sign_message.py index a7cdf85bf..584e79321 100644 --- a/src/apps/ethereum/sign_message.py +++ b/src/apps/ethereum/sign_message.py @@ -12,7 +12,7 @@ from apps.common.signverify import split_message def message_digest(message): h = HashWriter(sha3_256) - signed_message_header = '\x19Ethereum Signed Message:\n' + signed_message_header = "\x19Ethereum Signed Message:\n" h.extend(signed_message_header) h.extend(str(len(message))) h.extend(message) @@ -37,6 +37,6 @@ async def ethereum_sign_message(ctx, msg): async def require_confirm_sign_message(ctx, message): message = split_message(message) - text = Text('Sign ETH message') + text = Text("Sign ETH message") text.normal(*message) await require_confirm(ctx, text) diff --git a/src/apps/ethereum/sign_tx.py b/src/apps/ethereum/sign_tx.py index b00cc6377..283baaa7b 100644 --- a/src/apps/ethereum/sign_tx.py +++ b/src/apps/ethereum/sign_tx.py @@ -26,21 +26,32 @@ async def ethereum_sign_tx(ctx, msg): # detect ERC - 20 token token = None recipient = msg.to - value = int.from_bytes(msg.value, 'big') - if len(msg.to) == 20 and \ - len(msg.value) == 0 and \ - data_total == 68 and \ - len(msg.data_initial_chunk) == 68 and \ - msg.data_initial_chunk[:16] == b'\xa9\x05\x9c\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00': + value = int.from_bytes(msg.value, "big") + if ( + len(msg.to) == 20 + and len(msg.value) == 0 + and data_total == 68 + and len(msg.data_initial_chunk) == 68 + and msg.data_initial_chunk[:16] + == b"\xa9\x05\x9c\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + ): token = tokens.token_by_chain_address(msg.chain_id, msg.to) recipient = msg.data_initial_chunk[16:36] - value = int.from_bytes(msg.data_initial_chunk[36:68], 'big') + value = int.from_bytes(msg.data_initial_chunk[36:68], "big") await require_confirm_tx(ctx, recipient, value, msg.chain_id, token, msg.tx_type) if token is None and msg.data_length > 0: await require_confirm_data(ctx, msg.data_initial_chunk, data_total) - await require_confirm_fee(ctx, value, int.from_bytes(msg.gas_price, 'big'), int.from_bytes(msg.gas_limit, 'big'), msg.chain_id, token, msg.tx_type) + await require_confirm_fee( + ctx, + value, + int.from_bytes(msg.gas_price, "big"), + int.from_bytes(msg.gas_limit, "big"), + msg.chain_id, + token, + msg.tx_type, + ) data = bytearray() data += msg.data_initial_chunk @@ -97,6 +108,7 @@ def get_total_length(msg: EthereumSignTx, data_total: int) -> int: async def send_request_chunk(ctx, data_left: int): from trezor.messages.MessageType import EthereumTxAck + # TODO: layoutProgress ? req = EthereumTxRequest() if data_left <= 1024: @@ -129,24 +141,24 @@ async def send_signature(ctx, msg: EthereumSignTx, digest): def check(msg: EthereumSignTx): if msg.tx_type not in [1, 6, None]: - raise wire.DataError('tx_type out of bounds') + raise wire.DataError("tx_type out of bounds") if msg.chain_id < 0 or msg.chain_id > MAX_CHAIN_ID: - raise wire.DataError('chain_id out of bounds') + raise wire.DataError("chain_id out of bounds") if msg.data_length > 0: if not msg.data_initial_chunk: - raise wire.DataError('Data length provided, but no initial chunk') + raise wire.DataError("Data length provided, but no initial chunk") # Our encoding only supports transactions up to 2^24 bytes. To # prevent exceeding the limit we use a stricter limit on data length. if msg.data_length > 16000000: - raise wire.DataError('Data length exceeds limit') + raise wire.DataError("Data length exceeds limit") if len(msg.data_initial_chunk) > msg.data_length: - raise wire.DataError('Invalid size of initial chunk') + raise wire.DataError("Invalid size of initial chunk") # safety checks if not check_gas(msg) or not check_to(msg): - raise wire.DataError('Safety check failed') + raise wire.DataError("Safety check failed") def check_gas(msg: EthereumSignTx) -> bool: @@ -159,7 +171,7 @@ def check_gas(msg: EthereumSignTx) -> bool: def check_to(msg: EthereumTxRequest) -> bool: - if msg.to == b'': + if msg.to == b"": if msg.data_length == 0: # sending transaction to address 0 (contract creation) without a data field return False @@ -171,15 +183,15 @@ def check_to(msg: EthereumTxRequest) -> bool: def sanitize(msg): if msg.value is None: - msg.value = b'' + msg.value = b"" if msg.data_initial_chunk is None: - msg.data_initial_chunk = b'' + msg.data_initial_chunk = b"" if msg.data_length is None: msg.data_length = 0 if msg.to is None: - msg.to = b'' + msg.to = b"" if msg.nonce is None: - msg.nonce = b'' + msg.nonce = b"" if msg.chain_id is None: msg.chain_id = 0 return msg diff --git a/src/apps/ethereum/tokens.py b/src/apps/ethereum/tokens.py index 6a8032e56..8f457865d 100644 --- a/src/apps/ethereum/tokens.py +++ b/src/apps/ethereum/tokens.py @@ -10,720 +10,4300 @@ UNKNOWN_TOKEN = (None, None, None, None) # rest of the file is generated using trezor-common/ethereum_tokens-gen.py # DO NOT EDIT MANUALLY! tokens = [ - (64, b'\x99\x1e\x7f\xe4\xb0\x5f\x2b\x3d\xb1\xd7\x88\xe7\x05\x96\x3f\x5d\x64\x7b\x00\x44', 'MINING', 18), # ella / Ella Mining Tokens - (61, b'\x08\x5f\xb4\xf2\x40\x31\xea\xed\xbc\x2b\x61\x1a\xa5\x28\xf2\x23\x43\xeb\x52\xdb', 'BEC', 8), # etc / BEC - (61, b'\x5a\xce\x17\xf8\x7c\x73\x91\xe5\x79\x2a\x76\x83\x06\x9a\x80\x25\xb8\x3b\xbd\x85', 'PLAY', 0), # etc / Smart Billions - (1, b'\x4e\x84\xe9\xe5\xfb\x0a\x97\x26\x28\xcf\x45\x68\xc4\x03\x16\x7e\xf1\xd4\x04\x31', '$FFC', 18), # eth / $Fluzcoin - (1, b'\xa0\x24\xe8\x05\x7e\xec\x47\x4a\x9b\x23\x56\x83\x37\x07\xdd\x05\x79\xe2\x6e\xf3', '$FXY', 18), # eth / $FIXY NETWORK - (1, b'\x7d\xd7\xf5\x6d\x69\x7c\xc0\xf2\xb5\x2b\xd5\x5c\x05\x7f\x37\x8f\x1f\xe6\xab\x4b', '$TEAK', 18), # eth / $TEAK - (1, b'\xb6\xed\x76\x44\xc6\x94\x16\xd6\x7b\x52\x2e\x20\xbc\x29\x4a\x9a\x9b\x40\x5b\x31', '0xBTC', 8), # eth / 0xBitcoin - (1, b'\xaf\x30\xd2\xa7\xe9\x0d\x7d\xc3\x61\xc8\xc4\x58\x5e\x9b\xb7\xd2\xf6\xf1\x5b\xc7', '1ST', 18), # eth / FirstBlood - (1, b'\xfd\xbc\x1a\xdc\x26\xf0\xf8\xf8\x60\x6a\x5d\x63\xb7\xd3\xa3\xcd\x21\xc2\x2b\x23', '1WO', 8), # eth / 1WO - (1, b'\x9f\xc0\x58\x32\x20\xeb\x44\xfa\xee\x9e\x2d\xc1\xe6\x3f\x39\x20\x4d\xdd\x90\x90', '2DC', 18), # eth / DualChain - (1, b'\xae\xc9\x8a\x70\x88\x10\x41\x48\x78\xc3\xbc\xdf\x46\xaa\xd3\x1d\xed\x4a\x45\x57', '300', 18), # eth / 300 Token Sparta - (1, b'\xbd\xe8\xf7\x82\x0b\x55\x44\xa4\x9d\x34\xf9\xdd\xea\xca\xbe\xdc\x7c\x0b\x5a\xdc', 'A18', 0), # eth / Apollo18 - (1, b'\xb9\x8d\x4c\x97\x42\x5d\x99\x08\xe6\x6e\x53\xa6\xfd\xf6\x73\xac\xca\x0b\xe9\x86', 'ABT', 18), # eth / ArcBlock Token - (1, b'\x0e\x8d\x6b\x47\x1e\x33\x2f\x14\x0e\x7d\x9d\xbb\x99\xe5\xe3\x82\x2f\x72\x8d\xa6', 'ABYSS', 18), # eth / ABYSS - (1, b'\x13\xf1\xb7\xfd\xfb\xe1\xfc\x66\x67\x6d\x56\x48\x3e\x21\xb1\xec\xb4\x0b\x58\xe2', 'ACC', 18), # eth / Accelerator Network - (1, b'\xe6\x9a\x35\x3b\x31\x52\xdd\x7b\x70\x6f\xf7\xdd\x40\xfe\x1d\x18\xb7\x80\x2d\x31', 'ADH', 18), # eth / AdHive Token - (1, b'\x88\x10\xc6\x34\x70\xd3\x86\x39\x95\x4c\x6b\x41\xaa\xc5\x45\x84\x8c\x46\x48\x4a', 'ADI', 18), # eth / Aditus - (1, b'\x66\x0e\x71\x48\x37\x85\xf6\x61\x33\x54\x8b\x10\xf6\x92\x6d\xc3\x32\xb0\x6e\x61', 'ADL', 18), # eth / Adelphoi - (1, b'\x42\x28\x66\xa8\xf0\xb0\x32\xc5\xcf\x1d\xfb\xde\xf3\x1a\x20\xf4\x50\x95\x62\xb0', 'ADST', 0), # eth / AdShares - (1, b'\xd0\xd6\xd6\xc5\xfe\x4a\x67\x7d\x34\x3c\xc4\x33\x53\x6b\xb7\x17\xba\xe1\x67\xdd', 'ADT', 9), # eth / AdToken - (1, b'\x44\x70\xbb\x87\xd7\x7b\x96\x3a\x01\x3d\xb9\x39\xbe\x33\x2f\x92\x7f\x2b\x99\x2e', 'ADX', 4), # eth / AdEx Network - (1, b'\x5c\xa9\xa7\x1b\x1d\x01\x84\x9c\x0a\x95\x49\x0c\xc0\x05\x59\x71\x7f\xcf\x0d\x1d', 'AE', 18), # eth / aeternity - (1, b'\x8e\xb2\x43\x19\x39\x37\x16\x66\x8d\x76\x8d\xce\xc2\x93\x56\xae\x9c\xff\xe2\x85', 'AGI', 8), # eth / SingularityNET - (1, b'\x4c\xed\xa7\x90\x6a\x5e\xd2\x17\x97\x85\xcd\x3a\x40\xa6\x9e\xe8\xbc\x99\xc4\x66', 'AION', 8), # eth / Aion - (1, b'\x27\xdc\xe1\xec\x4d\x3f\x72\xc3\xe4\x57\xcc\x50\x35\x4f\x1f\x97\x5d\xde\xf4\x88', 'AIR', 8), # eth / AirToken - (1, b'\x10\x63\xce\x52\x42\x65\xd5\xa3\xa6\x24\xf4\x91\x4a\xcd\x57\x3d\xd8\x9c\xe9\x88', 'AIX', 18), # eth / Aigang - (1, b'\x18\x1a\x63\x74\x6d\x3a\xdc\xf3\x56\xcb\xc7\x3a\xce\x22\x83\x2f\xfb\xb1\xee\x5a', 'ALCO', 8), # eth / ALCO - (1, b'\xea\x61\x0b\x11\x53\x47\x77\x20\x74\x8d\xc1\x3e\xd3\x78\x00\x39\x41\xd8\x4f\xab', 'ALIS', 18), # eth / ALIS Token - (1, b'\x63\x8a\xc1\x49\xea\x8e\xf9\xa1\x28\x6c\x41\xb9\x77\x01\x7a\xa7\x35\x9e\x6c\xfa', 'ALTS', 18), # eth / ALTS Token - (1, b'\x4d\xc3\x64\x3d\xbc\x64\x2b\x72\xc1\x58\xe7\xf3\xd2\xff\x23\x2d\xf6\x1c\xb6\xce', 'AMB', 18), # eth / Amber Token - (1, b'\x94\x9b\xed\x88\x6c\x73\x9f\x1a\x32\x73\x62\x9b\x33\x20\xdb\x0c\x50\x24\xc7\x19', 'AMIS', 9), # eth / AMIS - (1, b'\x73\x7f\x98\xac\x8c\xa5\x9f\x2c\x68\xad\x65\x8e\x3c\x3d\x8c\x89\x63\xe4\x0a\x4c', 'AMN', 18), # eth / Amon - (1, b'\x38\xc8\x7a\xa8\x9b\x2b\x8c\xd9\xb9\x5b\x73\x6e\x1f\xa7\xb6\x12\xea\x97\x21\x69', 'AMO', 18), # eth / AMO Coin - (1, b'\x84\x93\x6c\xf7\x63\x0a\xa3\xe2\x7d\xd9\xaf\xf9\x68\xb1\x40\xd5\xae\xe4\x9f\x5a', 'AMTC', 8), # eth / AmberTime Coin - (1, b'\x96\x0b\x23\x6a\x07\xcf\x12\x26\x63\xc4\x30\x33\x50\x60\x9a\x66\xa7\xb2\x88\xc0', 'ANT', 18), # eth / ANT - (1, b'\x4c\x0f\xbe\x1b\xb4\x66\x12\x91\x5e\x79\x67\xd2\xc3\x21\x3c\xd4\xd8\x72\x57\xad', 'APIS', 18), # eth / APIS - (1, b'\x1a\x7a\x8b\xd9\x10\x6f\x2b\x8d\x97\x7e\x08\x58\x2d\xc7\xd2\x4c\x72\x3a\xb0\xdb', 'APPC', 18), # eth / AppCoins - (1, b'\x23\xae\x3c\x5b\x39\xb1\x2f\x06\x93\xe0\x54\x35\xee\xaa\x1e\x51\xd8\xc6\x15\x30', 'APT', 18), # eth / AIGang - (1, b'\xac\x70\x9f\xcb\x44\xa4\x3c\x35\xf0\xda\x4e\x31\x63\xb1\x17\xa1\x7f\x37\x70\xf5', 'ARC', 18), # eth / ARC - (1, b'\x12\x45\xef\x80\xf4\xd9\xe0\x2e\xd9\x42\x53\x75\xe8\xf6\x49\xb9\x22\x1b\x31\xd8', 'ARCT', 8), # eth / ArbitrageCT - (1, b'\x75\xaa\x7b\x0d\x02\x53\x2f\x38\x33\xb6\x6c\x7f\x0a\xd3\x53\x76\xd3\x73\xdd\xf8', 'ARD', 18), # eth / Accord - (1, b'\xba\x5f\x11\xb1\x6b\x15\x57\x92\xcf\x3b\x2e\x68\x80\xe8\x70\x68\x59\xa8\xae\xb6', 'ARN', 8), # eth / Aeron Token - (1, b'\xfe\xc0\xcf\x7f\xe0\x78\xa5\x00\xab\xf1\x5f\x12\x84\x95\x8f\x22\x04\x9c\x2c\x7e', 'ART', 18), # eth / ART - (1, b'\x77\x05\xfa\xa3\x4b\x16\xeb\x6d\x77\xdf\xc7\x81\x2b\xe2\x36\x7b\xa6\xb0\x24\x8e', 'ARX', 8), # eth / ARX - (1, b'\xb0\xd9\x26\xc1\xbc\x3d\x78\x06\x4f\x3e\x10\x75\xd5\xbd\x9a\x24\xf3\x5a\xe6\xc5', 'ARXT', 18), # eth / Assistive Reality ARX - (1, b'\x27\x05\x4b\x13\xb1\xb7\x98\xb3\x45\xb5\x91\xa4\xd2\x2e\x65\x62\xd4\x7e\xa7\x5a', 'AST', 4), # eth / Airswap - (1, b'\x17\x05\x2d\x51\xe9\x54\x59\x2c\x10\x46\x32\x0c\x23\x71\xab\xab\x6c\x73\xef\x10', 'ATH', 18), # eth / Athenian Warrior Token - (1, b'\x15\x43\xd0\xf8\x34\x89\xe8\x2a\x13\x44\xdf\x68\x27\xb2\x3d\x54\x1f\x23\x5a\x50', 'ATH (AIgatha Token)', 18), # eth / AIgatha Token - (1, b'\x78\xb7\xfa\xda\x55\xa6\x4d\xd8\x95\xd8\xc8\xc3\x57\x79\xdd\x8b\x67\xfa\x8a\x05', 'ATL', 18), # eth / ATL - (1, b'\x97\xae\xb5\x06\x6e\x1a\x59\x0e\x86\x8b\x51\x14\x57\xbe\xb6\xfe\x99\xd3\x29\xf5', 'ATMI', 18), # eth / Atonomi - (1, b'\x88\x78\x34\xd3\xb8\xd4\x50\xb6\xba\xb1\x09\xc2\x52\xdf\x3d\xa2\x86\xd7\x3c\xe4', 'ATT', 18), # eth / Atmatrix Token - (1, b'\x63\x39\x78\x4d\x94\x78\xda\x43\x10\x6a\x42\x91\x96\x77\x2a\x02\x9c\x2f\x17\x7d', 'ATTN', 18), # eth / Attention Token - (1, b'\xed\x24\x79\x80\x39\x6b\x10\x16\x9b\xb1\xd3\x6f\x6e\x27\x8e\xd1\x67\x00\xa6\x0f', 'AVA', 4), # eth / AVA - (1, b'\x0d\x88\xed\x6e\x74\xbb\xfd\x96\xb8\x31\x23\x16\x38\xb6\x6c\x05\x57\x1e\x82\x4f', 'AVT', 18), # eth / AVT - (1, b'\xcd\x4b\x4b\x0f\x32\x84\xa3\x3a\xc4\x9c\x67\x96\x1e\xc6\xe1\x11\x70\x83\x18\xcf', 'AX1', 5), # eth / AX1 Mining Token - (1, b'\x9a\xf2\xc6\xb1\xa2\x8d\x3d\x6b\xc0\x84\xbd\x26\x7f\x70\xe9\x0d\x49\x74\x1d\x5b', 'AXP', 8), # eth / AXP - (1, b'\xf8\x7f\x0d\x91\x53\xfe\xa5\x49\xc7\x28\xad\x61\xcb\x80\x15\x95\xa6\x8b\x73\xde', 'BANX', 18), # eth / BANX - (1, b'\x0d\x87\x75\xf6\x48\x43\x06\x79\xa7\x09\xe9\x8d\x2b\x0c\xb6\x25\x0d\x28\x87\xef', 'BAT', 18), # eth / BAT - (1, b'\x4a\x60\x58\x66\x6c\xf1\x05\x7e\xac\x3c\xd3\xa5\xa6\x14\x62\x05\x47\x55\x9f\xc9', 'BBK', 18), # eth / BRICKBLOCK TOKEN - (1, b'\x73\x67\xa6\x80\x39\xd4\x70\x4f\x30\xbf\xbf\x6d\x94\x80\x20\xc3\xb0\x7d\xfc\x59', 'BCBC', 18), # eth / Beercoin - (1, b'\x1e\x79\x7c\xe9\x86\xc3\xcf\xf4\x47\x2f\x7d\x38\xd5\xc4\xab\xa5\x5d\xfe\xfe\x40', 'BCDN', 15), # eth / BCDN - (1, b'\xac\xfa\x20\x9f\xb7\x3b\xf3\xdd\x5b\xbf\xb1\x10\x1b\x9b\xc9\x99\xc4\x90\x62\xa5', 'BCDT', 18), # eth / Blockchain Certified Data Token - (1, b'\xbc\x12\x34\x55\x2e\xbe\xa3\x2b\x51\x21\x19\x03\x56\xbb\xa6\xd3\xbb\x22\x5b\xb5', 'BCL', 18), # eth / BCL - (1, b'\x1c\x44\x81\x75\x0d\xaa\x5f\xf5\x21\xa2\xa7\x49\x0d\x99\x81\xed\x46\x46\x5d\xbd', 'BCPT', 18), # eth / BCPT - (1, b'\x10\x14\x61\x3e\x2b\x3c\xbc\x4d\x57\x50\x54\xd4\x98\x2e\x58\x0d\x9b\x99\xd7\xb1', 'BCV', 8), # eth / BitCapitalVendor Token - (1, b'\x19\x61\xb3\x33\x19\x69\xed\x52\x77\x07\x51\xfc\x71\x8e\xf5\x30\x83\x8b\x6d\xee', 'BDG', 18), # eth / BitDegree Token - (1, b'\x4d\x8f\xc1\x45\x3a\x0f\x35\x9e\x99\xc9\x67\x59\x54\xe6\x56\xd8\x0d\x99\x6f\xbf', 'BEE', 18), # eth / Bee Token - (1, b'\x74\xc1\xe4\xb8\xca\xe5\x92\x69\xec\x1d\x85\xd3\xd4\xf3\x24\x39\x60\x48\xf4\xac', 'BeerCoin', 0), # eth / BeerCoin - (1, b'\x6a\xeb\x95\xf0\x6c\xda\x84\xca\x34\x5c\x2d\xe0\xf3\xb7\xf9\x69\x23\xa4\x4f\x4c', 'BERRY', 14), # eth / Berry - (1, b'\x8a\xa3\x3a\x78\x99\xfc\xc8\xea\x5f\xbe\x6a\x60\x8a\x10\x9c\x38\x93\xa1\xb8\xb2', 'BET', 18), # eth / BET - (1, b'\x76\x31\x86\xeb\x8d\x48\x56\xd5\x36\xed\x44\x78\x30\x29\x71\x21\x4f\xeb\xc6\xa9', 'BETR', 18), # eth / BETR - (1, b'\xb2\xbf\xeb\x70\xb9\x03\xf1\xba\xac\x7f\x2b\xa2\xc6\x29\x34\xc7\xe5\xb9\x74\xc4', 'BKB', 8), # eth / BetKing Bankroll Token - (1, b'\x3c\xf9\xe0\xc3\x85\xa5\xab\xec\x9f\xd2\xa7\x17\x90\xaa\x34\x4c\x4e\x8e\x35\x70', 'BKRx', 18), # eth / BlockRx - (1, b'\x45\x24\x5b\xc5\x92\x19\xee\xaa\xf6\xcd\x3f\x38\x2e\x07\x8a\x46\x1f\xf9\xde\x7b', 'BKX', 18), # eth / BANKEX - (1, b'\x10\x7c\x45\x04\xcd\x79\xc5\xd2\x69\x6e\xa0\x03\x0a\x8d\xd4\xe9\x26\x01\xb8\x2e', 'BLT', 18), # eth / Bloom - (1, b'\x53\x9e\xfe\x69\xbc\xdd\x21\xa8\x3e\xfd\x91\x22\x57\x1a\x64\xcc\x25\xe0\x28\x2b', 'BLUE', 8), # eth / Ethereum Blue - (1, b'\xce\x59\xd2\x9b\x09\xaa\xe5\x65\xfe\xee\xf8\xe5\x2f\x47\xc3\xcd\x53\x68\xc6\x63', 'BLX (Bullion)', 18), # eth / Bullion Crypto - (1, b'\xe5\xa7\xc1\x29\x72\xf3\xbb\xfe\x70\xed\x29\x52\x1c\x89\x49\xb8\xaf\x6a\x09\x70', 'BLX (Iconomi)', 18), # eth / Iconomi - (1, b'\x57\x32\x04\x6a\x88\x37\x04\x40\x4f\x28\x4c\xe4\x1f\xfa\xdd\x5b\x00\x7f\xd6\x68', 'BLZ', 18), # eth / Bluezelle - (1, b'\xdf\x6e\xf3\x43\x35\x07\x80\xbf\x8c\x34\x10\xbf\x06\x2e\x0c\x01\x5b\x1d\xd6\x71', 'BMC', 8), # eth / Blackmoon Crypto BMC Token - (1, b'\xf0\x28\xad\xee\x51\x53\x3b\x1b\x47\xbe\xaa\x89\x0f\xeb\x54\xa4\x57\xf5\x1e\x89', 'BMT', 18), # eth / BMT - (1, b'\x98\x6e\xe2\xb9\x44\xc4\x2d\x01\x7f\x52\xaf\x21\xc4\xc6\x9b\x84\xdb\xea\x35\xd8', 'BMX', 18), # eth / BitMartToken - (1, b'\xb8\xc7\x74\x82\xe4\x5f\x1f\x44\xde\x17\x45\xf5\x2c\x74\x42\x6c\x63\x1b\xdd\x52', 'BNB', 18), # eth / BNB - (1, b'\xdd\x6b\xf5\x6c\xa2\xad\xa2\x4c\x68\x3f\xac\x50\xe3\x77\x83\xe5\x5b\x57\xaf\x9f', 'BNC', 12), # eth / BNC - (1, b'\xda\x2c\x42\x4f\xc9\x8c\x74\x1c\x2d\x4e\xf2\xf4\x28\x97\xce\xfe\xd8\x97\xca\x75', 'BNFT', 9), # eth / Benefits Coin - (1, b'\x1f\x57\x3d\x6f\xb3\xf1\x3d\x68\x9f\xf8\x44\xb4\xce\x37\x79\x4d\x79\xa7\xff\x1c', 'BNT', 18), # eth / Bancor - (1, b'\xd2\xd6\x15\x86\x83\xae\xe4\xcc\x83\x80\x67\x72\x72\x09\xa0\xaa\xf4\x35\x9d\xe3', 'BNTY', 18), # eth / Bounty0x Token - (1, b'\xdf\x34\x79\x11\x91\x0b\x6c\x9a\x42\x86\xba\x8e\x2e\xe5\xea\x4a\x39\xeb\x21\x34', 'BOB', 18), # eth / Bob's repair - (1, b'\xcc\x34\x36\x6e\x38\x42\xca\x1b\xd3\x6c\x1f\x32\x4d\x15\x25\x79\x60\xfc\xc8\x01', 'BON', 18), # eth / Bonpay - (1, b'\x7f\x1e\x2c\x7d\x6a\x69\xbf\x34\x82\x4d\x72\xc5\x3b\x45\x50\xe8\x95\xc0\xd8\xc2', 'BOP', 8), # eth / BlockOptiopns Token - (1, b'\xc2\xc6\x3f\x23\xec\x5e\x97\xef\xbd\x75\x65\xdf\x9e\xc7\x64\xfd\xc7\xd4\xe9\x1d', 'BOU', 18), # eth / Boule Coin - (1, b'\x32\x76\x82\x77\x9b\xab\x2b\xf4\xd1\x33\x7e\x89\x74\xab\x9d\xe8\x27\x5a\x7c\xa8', 'BPT', 18), # eth / Blockport Token - (1, b'\x5a\xf2\xbe\x19\x3a\x6a\xbc\xa9\xc8\x81\x70\x01\xf4\x57\x44\x77\x7d\xb3\x07\x56', 'BQX', 8), # eth / Bitquence - (1, b'\x9e\x77\xd5\xa1\x25\x1b\x6f\x7d\x45\x67\x22\xa6\xea\xc6\xd2\xd5\x98\x0b\xd8\x91', 'BRAT', 8), # eth / BRAT - (1, b'\x55\x8e\xc3\x15\x2e\x2e\xb2\x17\x49\x05\xcd\x19\xae\xa4\xe3\x4a\x23\xde\x9a\xd6', 'BRD', 18), # eth / Bread - (1, b'\xf2\x6e\xf5\xe0\x54\x53\x84\xb7\xdc\xc0\xf2\x97\xf2\x67\x41\x89\x58\x68\x30\xdf', 'BSDC', 18), # eth / BSDC - (1, b'\x50\x9a\x38\xb7\xa1\xcc\x0d\xcd\x83\xaa\x9d\x06\x21\x46\x63\xd9\xec\x7c\x7f\x4a', 'BST', 18), # eth / BlocksquareToken - (1, b'\x08\x86\x94\x9c\x1b\x8c\x41\x28\x60\xc4\x26\x4c\xeb\x80\x83\xd1\x36\x5e\x86\xcf', 'BTCE', 8), # eth / EthereumBitcoin - (1, b'\x5a\xcd\x19\xb9\xc9\x1e\x59\x6b\x1f\x06\x2f\x18\xe3\xd0\x2d\xa7\xed\x8d\x1e\x50', 'BTCL', 8), # eth / BTC Lite - (1, b'\x73\xdd\x06\x9c\x29\x9a\x5d\x69\x1e\x98\x36\x24\x3b\xca\xec\x9c\x8c\x1d\x87\x34', 'BTE', 8), # eth / BTE - (1, b'\xfa\xd5\x72\xdb\x56\x6e\x52\x34\xac\x9f\xc3\xd5\x70\xc4\xed\xc0\x05\x0e\xaa\x92', 'BTH', 18), # eth / Bytether - (1, b'\xa0\x2e\x3b\xb9\xce\xbc\x03\x95\x26\x01\xb3\x72\x4b\x49\x40\xe0\x84\x5b\xeb\xcf', 'BTHR', 18), # eth / Bethereum - (1, b'\xdb\x86\x46\xf5\xb4\x87\xb5\xdd\x97\x9f\xac\x61\x83\x50\xe8\x50\x18\xf5\x57\xd4', 'BTK', 18), # eth / Bitcoin Token - (1, b'\x2a\xcc\xab\x9c\xb7\xa4\x8c\x3e\x82\x28\x6f\x0b\x2f\x87\x98\xd2\x01\xf4\xec\x3f', 'BTL (Battle)', 18), # eth / BTL (Battle) - (1, b'\x92\x68\x5e\x93\x95\x65\x37\xc2\x5b\xb7\x5d\x5d\x47\xfc\xa4\x26\x6d\xd6\x28\xb8', 'BTL (Bitlle)', 4), # eth / Bitlle Token - (1, b'\xcb\x97\xe6\x5f\x07\xda\x24\xd4\x6b\xcd\xd0\x78\xeb\xeb\xd7\xc6\xe6\xe3\xd7\x50', 'BTM', 8), # eth / Bytom - (1, b'\x16\xb0\xe6\x2a\xc1\x3a\x2f\xae\xd3\x6d\x18\xbc\xe2\x35\x6d\x25\xab\x3c\xfa\xd3', 'BTQ', 18), # eth / Bitcoin Boutique - (1, b'\x08\x0a\xa0\x7e\x2c\x71\x85\x15\x0d\x7e\x4d\xa9\x88\x38\xa8\xd2\xfe\xac\x3d\xfc', 'BTT', 0), # eth / Bitether - (1, b'\xfa\x45\x6c\xf5\x52\x50\xa8\x39\x08\x8b\x27\xee\x32\xa4\x24\xd7\xda\xcb\x54\xff', 'BTTX', 18), # eth / Blocktrade.com - (1, b'\xca\x3c\x18\xa6\x5b\x80\x2e\xc2\x67\xf8\xf4\x80\x25\x45\xe7\xf5\x3d\x24\xc7\x5e', 'BUC', 18), # eth / BeeUnity Chain - (1, b'\x26\xe7\x53\x07\xfc\x0c\x02\x14\x72\xfe\xb8\xf7\x27\x83\x95\x31\xf1\x12\xf3\x17', 'C20', 18), # eth / Crypto20's Token - (1, b'\xd4\x2d\xeb\xe4\xed\xc9\x2b\xd5\xa3\xfb\xb4\x24\x3e\x1e\xcc\xf6\xd6\x3a\x4a\x5d', 'C8', 18), # eth / Carboneum - (1, b'\x7d\x4b\x8c\xce\x05\x91\xc9\x04\x4a\x22\xee\x54\x35\x33\xb7\x2e\x97\x6e\x36\xc3', 'CAG', 18), # eth / Change Bank - (1, b'\x1d\x46\x24\x14\xfe\x14\xcf\x48\x9c\x7a\x21\xca\xc7\x85\x09\xf4\xbf\x8c\xd7\xc0', 'CAN', 6), # eth / CAN - (1, b'\x42\x3e\x43\x22\xcd\xda\x29\x15\x6b\x49\xa1\x7d\xfb\xd2\xac\xc4\xb2\x80\x60\x0d', 'CAR', 9), # eth / Car Sharing Community - (1, b'\xa5\x17\xa4\x6b\xaa\xd6\xb0\x54\xa7\x6b\xd1\x9c\x46\x84\x4f\x71\x7f\xe6\x9f\xea', 'CARB', 8), # eth / CarbCoin - (1, b'\x21\x08\xe6\x2d\x33\x5b\xbd\xc8\x9e\xc3\xe9\xd8\x58\x2f\x18\xdc\xfb\x0c\xdf\xf4', 'CARCO', 8), # eth / CARCO - (1, b'\x1e\xd2\xb1\xea\xed\x8e\x96\x8b\xc3\x6e\xb9\x0a\x91\x46\x60\xa7\x18\x27\xa5\xe9', 'CARD', 0), # eth / Cardstack Token - (1, b'\xbf\x18\xf2\x46\xb9\x30\x1f\x23\x1e\x95\x61\xb3\x5a\x38\x79\x76\x9b\xb4\x63\x75', 'CARE', 18), # eth / Token CARE - (1, b'\xe8\x78\x0b\x48\xbd\xb0\x5f\x92\x86\x97\xa5\xe8\x15\x5f\x67\x2e\xd9\x14\x62\xf7', 'CAS', 18), # eth / Cashaa - (1, b'\x12\x34\x56\x74\x61\xd3\xf8\xdb\x74\x96\x58\x17\x74\xbd\x86\x9c\x83\xd5\x1c\x93', 'CAT (BitClave)', 18), # eth / CAT (BitClave) - (1, b'\x56\xba\x2e\xe7\x89\x04\x61\xf4\x63\xf7\xbe\x02\xaa\xc3\x09\x9f\x6d\x58\x11\xa8', 'CAT (Blockcat)', 18), # eth / CAT (Blockcat) - (1, b'\x68\xe1\x4b\xb5\xa4\x5b\x96\x81\x32\x7e\x16\xe5\x28\x08\x4b\x9d\x96\x2c\x1a\x39', 'CATs (BitClave)_Old', 18), # eth / CATs (BitClave)_Old - (1, b'\xc1\x66\x03\x87\x05\xff\xba\xb3\x79\x41\x85\xb3\xa9\xd9\x25\x63\x2a\x1d\xf3\x7d', 'CC3', 18), # eth / Coal Coin - (1, b'\x28\x57\x7a\x6d\x31\x55\x9b\xd2\x65\xce\x3a\xdb\x62\xd0\x45\x85\x50\xf7\xb8\xa7', 'CCC (CryptoCrashCourse)', 18), # eth / CryptoCrashCourse - (1, b'\xbe\x11\xee\xb1\x86\xe6\x24\xb8\xf2\x6a\x50\x45\x57\x5a\x13\x40\xe4\x05\x45\x52', 'CCC (ICONOMI)', 18), # eth / CCC (ICONOMI) - (1, b'\xd3\x48\xe0\x7a\x28\x06\x50\x5b\x85\x61\x23\x04\x5d\x27\xae\xed\x90\x92\x4b\x50', 'CCLC', 8), # eth / Christ Coin - (1, b'\x31\x5c\xe5\x9f\xaf\xd3\xa8\xd5\x62\xb7\xec\x1c\x85\x42\x38\x2d\x27\x10\xb0\x6c', 'CCS', 18), # eth / CacaoShares - (1, b'\x8a\x95\xca\x44\x8a\x52\xc0\xad\xf0\x05\x4b\xb3\x40\x2d\xc5\xe0\x9c\xd6\xb2\x32', 'CDL', 18), # eth / Confideal - (1, b'\x17\x7d\x39\xac\x67\x6e\xd1\xc6\x7a\x2b\x26\x8a\xd7\xf1\xe5\x88\x26\xe5\xb0\xaf', 'CDT', 18), # eth / CoinDash - (1, b'\x6f\xff\x38\x06\xbb\xac\x52\xa2\x0e\x0d\x79\xbc\x53\x8d\x52\x7f\x6a\x22\xc9\x6b', 'CDX', 18), # eth / CDX - (1, b'\x2c\xb1\x01\xd7\xda\x0e\xba\xa5\x7d\x3f\x2f\xef\x46\xd7\xff\xb7\xbb\x64\x59\x2b', 'CDX', 0), # eth / Carbon Dollar X - (1, b'\xb0\x56\xc3\x8f\x6b\x7d\xc4\x06\x43\x67\x40\x3e\x26\x42\x4c\xd2\xc6\x06\x55\xe1', 'CEEK', 18), # eth / CEEK VR Token - (1, b'\x12\xfe\xf5\xe5\x7b\xf4\x58\x73\xcd\x9b\x62\xe9\xdb\xd7\xbf\xb9\x9e\x32\xd7\x3e', 'CFI', 18), # eth / Cofound.it - (1, b'\x69\x56\x98\x3f\x8b\x3c\xe1\x73\xb4\xab\x84\x36\x1a\xa0\xad\x52\xf3\x8d\x93\x6f', 'CFTY', 8), # eth / Crafty Token - (1, b'\xba\x9d\x41\x99\xfa\xb4\xf2\x6e\xfe\x35\x51\xd4\x90\xe3\x82\x14\x86\xf1\x35\xba', 'CHSB', 8), # eth / CHSB - (1, b'\x06\x01\x2c\x8c\xf9\x7b\xea\xd5\xde\xae\x23\x70\x70\xf9\x58\x7f\x8e\x7a\x26\x6d', 'CK', 0), # eth / CK - (1, b'\xb1\xc1\xcb\x8c\x7c\x19\x92\xdb\xa2\x4e\x62\x8b\xf7\xd3\x8e\x71\xda\xd4\x6a\xeb', 'CLB', 18), # eth / Cloudbric - (1, b'\x3d\xc9\xa4\x2f\xa7\xaf\xe5\x7b\xe0\x3c\x58\xfd\x7f\x44\x11\xb1\xe4\x66\xc5\x08', 'CLL', 18), # eth / CryptoLiveLeak - (1, b'\x41\x62\x17\x8b\x78\xd6\x98\x54\x80\xa3\x08\xb2\x19\x0e\xe5\x51\x74\x60\x40\x6d', 'CLN', 18), # eth / ColuLocalNetwork - (1, b'\x7f\xce\x28\x56\x89\x9a\x68\x06\xee\xef\x70\x80\x79\x85\xfc\x75\x54\xc6\x63\x40', 'CLP', 9), # eth / CryptoLending - (1, b'\x3e\xdd\x23\x5c\x3e\x84\x0c\x1f\x29\x28\x6b\x2e\x39\x37\x0a\x25\x5c\x7b\x6f\xdb', 'CMBT', 8), # eth / CMBToken - (1, b'\x7e\x66\x75\x25\x52\x1c\xf6\x13\x52\xe2\xe0\x1b\x50\xfa\xaa\xe7\xdf\x39\x74\x9a', 'CMC', 18), # eth / CryptoMart - (1, b'\xf8\x5f\xee\xa2\xfd\xd8\x1d\x51\x17\x7f\x6b\x8f\x35\xf0\xe6\x73\x4c\xe4\x5f\x5f', 'CMT', 18), # eth / CyberMiles Token - (1, b'\xeb\xf2\xf9\xe8\xde\x96\x0f\x64\xec\x0f\xdc\xda\x6c\xb2\x82\x42\x31\x33\x34\x7b', 'CNB', 8), # eth / Canabio - (1, b'\xd4\xc4\x35\xf5\xb0\x9f\x85\x5c\x33\x17\xc8\x52\x4c\xb1\xf5\x86\xe4\x27\x95\xfa', 'CND', 18), # eth / Cindicator - (1, b'\xb4\xb1\xd2\xc2\x17\xec\x07\x76\x58\x4c\xe0\x8d\x3d\xd9\x8f\x90\xed\xed\xa4\x4b', 'CO2', 18), # eth / Climatecoin - (1, b'\x57\x4b\x36\xbc\xed\x44\x33\x38\x87\x5d\x17\x1c\xc3\x77\xe6\x91\xf7\xd4\xf8\x87', 'CO2Bit', 18), # eth / CO2Bit - (1, b'\xb2\xf7\xeb\x1f\x2c\x37\x64\x5b\xe6\x1d\x73\x95\x30\x35\x36\x0e\x76\x8d\x81\xe6', 'COB', 18), # eth / Cobinhood Token - (1, b'\x31\x36\xef\x85\x15\x92\xac\xf4\x9c\xa4\xc8\x25\x13\x1e\x36\x41\x70\xfa\x32\xb3', 'COFI', 18), # eth / CoinFi Token - (1, b'\x0c\x91\xb0\x15\xab\xa6\xf7\xb4\x73\x8d\xcd\x36\xe7\x41\x01\x38\xb2\x9a\xdc\x29', 'COIL', 8), # eth / CoinOil - (1, b'\x5e\x8f\x85\x59\x66\xd6\x38\x13\x5a\x96\x88\x61\xe8\x0d\xda\x72\x22\x91\xb0\x6d', 'COIN', 18), # eth / Coinvest V2 Token - (1, b'\x65\x29\x2e\xea\xdf\x14\x26\xcd\x2d\xf1\xc4\x79\x3a\x3d\x75\x19\xf2\x53\x91\x3b', 'COSS', 18), # eth / Coss Token - (1, b'\x9e\x96\x60\x44\x45\xec\x19\xff\xed\x9a\x5e\x8d\xd7\xb5\x0a\x29\xc8\x99\xa1\x0c', 'COSS', 18), # eth / Coss Token - (1, b'\xe2\xfb\x65\x29\xef\x56\x6a\x08\x0e\x6d\x23\xde\x0b\xd3\x51\x31\x10\x87\xd5\x67', 'COV', 18), # eth / Covesting - (1, b'\xb7\x87\xd4\xea\xc8\x89\x97\x30\xbb\x8c\x57\xfc\x3c\x99\x8c\x49\xc5\x24\x4e\xc0', 'CPEX', 8), # eth / CoinPulseToken - (1, b'\xf4\x47\x45\xfb\xd4\x1f\x6a\x1b\xa1\x51\xdf\x19\x0d\xb0\x56\x4c\x5f\xcc\x44\x10', 'CPY', 18), # eth / COPYTRACK - (1, b'\x7f\x58\x5b\x91\x30\xc6\x4e\x9e\x9f\x47\x0b\x61\x8a\x7b\xad\xd0\x3d\x79\xca\x7e', 'CR7', 18), # eth / CR7Coin - (1, b'\xae\xf3\x8f\xbf\xbf\x93\x2d\x1a\xef\x3b\x80\x8b\xc8\xfb\xd8\xcd\x8e\x1f\x8b\xc5', 'CRB', 8), # eth / CRB - (1, b'\x67\x2a\x1a\xd4\xf6\x67\xfb\x18\xa3\x33\xaf\x13\x66\x7a\xa0\xaf\x1f\x5b\x5b\xdd', 'CRED', 18), # eth / CRED - (1, b'\x4e\x06\x03\xe2\xa2\x7a\x30\x48\x0e\x5e\x3a\x4f\xe5\x48\xe2\x9e\xf1\x2f\x64\xbe', 'CREDO', 18), # eth / Credo / Bitbounce - (1, b'\x80\xa7\xe0\x48\xf3\x7a\x50\x50\x03\x51\xc2\x04\xcb\x40\x77\x66\xfa\x3b\xae\x7f', 'CRPT', 18), # eth / CrypteriumToken - (1, b'\xf0\xda\x11\x86\xa4\x97\x72\x26\xb9\x13\x5d\x06\x13\xee\x72\xe2\x29\xec\x3f\x4d', 'CRT', 18), # eth / CreamtoeCoin - (1, b'\xe4\xc9\x4d\x45\xf7\xae\xf7\x01\x8a\x5d\x66\xf4\x4a\xf7\x80\xec\x60\x23\x37\x8e', 'CryptoCarbon', 6), # eth / CryptoCarbon - (1, b'\x45\x45\x75\x0f\x39\xaf\x6b\xe4\xf2\x37\xb6\x86\x9d\x4e\xcc\xa9\x28\xfd\x5a\x85', 'CTF', 18), # eth / CryptoTask - (1, b'\xc8\x7c\x5d\xd8\x6a\x3d\x56\x7f\xf2\x87\x01\x88\x6f\xb0\x74\x5a\xaa\x89\x8d\xa4', 'CTG', 18), # eth / CT Global Token - (1, b'\xbf\x4c\xfd\x7d\x1e\xde\xee\xa5\xf6\x60\x08\x27\x41\x1b\x41\xa2\x1e\xb0\x8a\xbd', 'CTL', 2), # eth / CTL - (1, b'\xe3\xfa\x17\x7a\xce\xcf\xb8\x67\x21\xcf\x6f\x9f\x42\x06\xbd\x3b\xd6\x72\xd7\xd5', 'CTT', 18), # eth / ChainTrade Token - (1, b'\x66\x2a\xbc\xad\x0b\x7f\x34\x5a\xb7\xff\xb1\xb1\xfb\xb9\xdf\x78\x94\xf1\x8e\x66', 'CTX', 18), # eth / CarTaxi - (1, b'\xda\x6c\xb5\x8a\x0d\x0c\x01\x61\x0a\x29\xc5\xa6\x5c\x30\x3e\x13\xe8\x85\x88\x7c', 'cV', 18), # eth / carVertical - (1, b'\x41\xe5\x56\x00\x54\x82\x4e\xa6\xb0\x73\x2e\x65\x6e\x3a\xd6\x4e\x20\xe9\x4e\x45', 'CVC', 8), # eth / CVC - (1, b'\x21\x34\x05\x7c\x0b\x46\x1f\x89\x8d\x37\x5c\xea\xd6\x52\xac\xae\x62\xb5\x95\x41', 'CXC', 18), # eth / CoxxxCoin - (1, b'\xb6\xee\x96\x68\x77\x1a\x79\xbe\x79\x67\xee\x29\xa6\x3d\x41\x84\xf8\x09\x71\x43', 'CXO', 18), # eth / CargoX - (1, b'\xda\xb0\xc3\x1b\xf3\x4c\x89\x7f\xb0\xfe\x90\xd1\x2e\xc9\x40\x1c\xaf\x5c\x36\xec', 'DAB', 0), # eth / DAB - (1, b'\xfb\x2f\x26\xf2\x66\xfb\x28\x05\xa3\x87\x23\x0f\x2a\xa0\xa3\x31\xb4\xd9\x6f\xba', 'DADI', 18), # eth / DADI - (1, b'\x89\xd2\x4a\x6b\x4c\xcb\x1b\x6f\xaa\x26\x25\xfe\x56\x2b\xdd\x9a\x23\x26\x03\x59', 'DAI', 18), # eth / Dai Stablecoin v1.0 - (1, b'\x07\xd9\xe4\x9e\xa4\x02\x19\x4b\xf4\x8a\x82\x76\xda\xfb\x16\xe4\xed\x63\x33\x17', 'DALC', 8), # eth / DaleCoin - (1, b'\x9b\x70\x74\x0e\x70\x8a\x08\x3c\x6f\xf3\x8d\xf5\x22\x97\x02\x0f\x5d\xfa\xa5\xee', 'DAN', 10), # eth / DaneelToken - (1, b'\xbb\x9b\xc2\x44\xd7\x98\x12\x3f\xde\x78\x3f\xcc\x1c\x72\xd3\xbb\x8c\x18\x94\x13', 'DAO', 16), # eth / DAO - (1, b'\x81\xc9\x15\x1d\xe0\xc8\xba\xfc\xd3\x25\xa5\x7e\x3d\xb5\xa5\xdf\x1c\xeb\xf7\x9c', 'DAT', 18), # eth / Datum Token - (1, b'\x1b\x5f\x21\xee\x98\xee\xd4\x8d\x29\x2e\x8e\x2d\x3e\xd8\x2b\x40\xa9\x72\x8a\x22', 'DATABroker', 18), # eth / DataBrokerDAO Token - (1, b'\x0c\xf0\xee\x63\x78\x8a\x08\x49\xfe\x52\x97\xf3\x40\x7f\x70\x1e\x12\x2c\xc0\x23', 'DATACoin', 18), # eth / DATACoin - (1, b'\xd8\x2d\xf0\xab\xd3\xf5\x14\x25\xeb\x15\xef\x75\x80\xfd\xa5\x57\x27\x87\x5f\x14', 'DAV', 18), # eth / DAV Token - (1, b'\x61\x72\x5f\x3d\xb4\x00\x4a\xfe\x01\x47\x45\xb2\x1d\xab\x1e\x16\x77\xcc\x32\x8b', 'DAXT', 18), # eth / Digital Asset Exchange Token - (1, b'\xe8\x14\xae\xe9\x60\xa8\x52\x08\xc3\xdb\x54\x2c\x53\xe7\xd4\xa6\xc8\xd5\xf6\x0f', 'DAY', 18), # eth / ChronoLogic DAY - (1, b'\x38\x6f\xaa\x47\x03\xa3\x4a\x7f\xdb\x19\xbe\xc2\xe1\x4f\xd4\x27\xc9\x63\x84\x16', 'DCA', 18), # eth / DoBetAcceptBet - (1, b'\x39\x9a\x0e\x6f\xbe\xb3\xd7\x4c\x85\x35\x74\x39\xf4\xc8\xae\xd9\x67\x8a\x5c\xbf', 'DCL', 3), # eth / DCL - (1, b'\x08\xd3\x2b\x0d\xa6\x3e\x2c\x3b\xcf\x80\x19\xc9\xc5\xd8\x49\xd7\xa9\xd7\x91\xe6', 'DCN', 0), # eth / Dentacoin - (1, b'\xcc\x4e\xf9\xee\xaf\x65\x6a\xc1\xa2\xab\x88\x67\x43\xe9\x8e\x97\xe0\x90\xed\x38', 'DDF', 18), # eth / DDF - (1, b'\x15\x12\x02\xc9\xc1\x8e\x49\x56\x56\xf3\x72\x28\x1f\x49\x3e\xb7\x69\x89\x61\xd5', 'DEB', 18), # eth / DEBITUM - (1, b'\x07\x5c\x60\xee\x2c\xd3\x08\xff\x47\x87\x3b\x38\xbd\x9a\x0f\xa5\x85\x33\x82\xc4', 'DEEZ', 18), # eth / DeezNuts - (1, b'\x35\x97\xbf\xd5\x33\xa9\x9c\x9a\xa0\x83\x58\x7b\x07\x44\x34\xe6\x1e\xb0\xa2\x58', 'DENT', 8), # eth / DENT - (1, b'\x7c\xf2\x71\x96\x6f\x36\x34\x3b\xf0\x15\x0f\x25\xe5\x36\x4f\x79\x61\xc5\x82\x01', 'DEPO', 0), # eth / CRYPTODEPOZIT - (1, b'\xdd\x94\xde\x9c\xfe\x06\x35\x77\x05\x1a\x5e\xb7\x46\x5d\x08\x31\x7d\x88\x08\xb6', 'Devcon2 Token', 0), # eth / Devcon2 Token - (1, b'\xe0\xb7\x92\x7c\x4a\xf2\x37\x65\xcb\x51\x31\x4a\x0e\x05\x21\xa9\x64\x5f\x0e\x2a', 'DGD', 9), # eth / Digix DAO - (1, b'\xf6\xcf\xe5\x3d\x6f\xeb\xae\xea\x05\x1f\x40\x0f\xf5\xfc\x14\xf0\xcb\xbd\xac\xa1', 'DGPT', 18), # eth / DigiPulse - (1, b'\x55\xb9\xa1\x1c\x2e\x83\x51\xb4\xff\xc7\xb1\x15\x61\x14\x8b\xfa\xc9\x97\x78\x55', 'DGX', 9), # eth / DGX - (1, b'\x2e\x07\x1d\x29\x66\xaa\x7d\x8d\xec\xb1\x00\x58\x85\xba\x19\x77\xd6\x03\x8a\x65', 'DICE', 16), # eth / Etheroll - (1, b'\x13\xf1\x1c\x99\x05\xa0\x8c\xa7\x6e\x3e\x85\x3b\xe6\x3d\x4f\x09\x44\x32\x6c\x72', 'DIVX', 18), # eth / DIVX - (1, b'\xba\x18\x7b\x09\xff\xa8\xdd\xdc\x80\xd2\x57\x1e\xd3\xcb\xc4\xbe\x0a\xf6\x9e\x0c', 'DKP', 18), # eth / Draggin Karma Points - (1, b'\x07\xe3\xc7\x06\x53\x54\x8b\x04\xf0\xa7\x59\x70\xc1\xf8\x1b\x4c\xbb\xfb\x60\x6f', 'DLT', 18), # eth / Agrello - (1, b'\x2c\xcb\xff\x3a\x04\x2c\x68\x71\x6e\xd2\xa2\xcb\x0c\x54\x4a\x9f\x1d\x19\x35\xe1', 'DMT', 8), # eth / DMarket Token - (1, b'\x0a\xbd\xac\xe7\x0d\x37\x90\x23\x5a\xf4\x48\xc8\x85\x47\x60\x3b\x94\x56\x04\xea', 'DNT', 18), # eth / DistrictOx - (1, b'\xe4\x3e\x20\x41\xdc\x37\x86\xe1\x66\x96\x1e\xd9\x48\x4a\x55\x39\x03\x3d\x10\xfb', 'DNX', 18), # eth / DenCity - (1, b'\x76\x97\x4c\x7b\x79\xdc\x8a\x6a\x10\x9f\xd7\x1f\xd7\xce\xb9\xe4\x0e\xff\x53\x82', 'DOW', 18), # eth / DOW - (1, b'\xee\xf6\xe9\x00\x34\xee\xa8\x9e\x31\xeb\x4b\x8e\xac\xd3\x23\xf2\x8a\x92\xea\xe4', 'DOW', 18), # eth / DOW - (1, b'\x01\xb3\xec\x4a\xae\x1b\x87\x29\x52\x9b\xeb\x49\x65\xf2\x7d\x00\x87\x88\xb0\xeb', 'DPP', 18), # eth / Digital Assets Power Play - (1, b'\x41\x9c\x4d\xb4\xb9\xe2\x5d\x6d\xb2\xad\x96\x91\xcc\xb8\x32\xc8\xd9\xfd\xa0\x5e', 'DRGN', 18), # eth / Dragon - (1, b'\x3c\x75\x22\x65\x55\xfc\x49\x61\x68\xd4\x8b\x88\xdf\x83\xb9\x5f\x16\x77\x1f\x37', 'DROP', 0), # eth / Droplex - (1, b'\x46\x72\xba\xd5\x27\x10\x74\x71\xcb\x50\x67\xa8\x87\xf4\x65\x6d\x58\x5a\x8a\x31', 'DROP (dropil)', 18), # eth / Dropil - (1, b'\x27\x99\xd9\x0c\x6d\x44\xcb\x9a\xa5\xfb\xc3\x77\x17\x7f\x16\xc3\x3e\x05\x6b\x82', 'DRP', 0), # eth / Dripcoin - (1, b'\x62\x1d\x78\xf2\xef\x2f\xd9\x37\xbf\xca\x69\x6c\xab\xaf\x9a\x77\x9f\x59\xb3\xed', 'DRP', 2), # eth / DCorp - (1, b'\x1e\x09\xbd\x8c\xad\xb4\x41\x63\x2e\x44\x1d\xb3\xe1\xd7\x99\x09\xee\x0a\x22\x56', 'DSC', 1), # eth / Digital Safe Coin - (1, b'\x5a\xdc\x96\x1d\x6a\xc3\xf7\x06\x2d\x2e\xa4\x5f\xef\xb8\xd8\x16\x7d\x44\xb1\x90', 'DTH', 18), # eth / dether - (1, b'\xd2\x34\xbf\x24\x10\xa0\x00\x9d\xf9\xc3\xc6\x3b\x61\x0c\x09\x73\x8f\x18\xcc\xd7', 'DTR', 8), # eth / DTR - (1, b'\xf9\xf7\xc2\x9c\xfd\xf1\x9f\xcf\x1f\x2a\xa6\xb8\x4a\xa3\x67\xbc\xf1\xbd\x16\x76', 'DTT', 18), # eth / Delphi Tech Token - (1, b'\x76\x5f\x0c\x16\xd1\xdd\xc2\x79\x29\x5c\x1a\x7c\x24\xb0\x88\x3f\x62\xd3\x3f\x75', 'DTX', 18), # eth / DaTa eXchange Token - (1, b'\x82\xfd\xed\xfb\x76\x35\x44\x1a\xa5\xa9\x27\x91\xd0\x01\xfa\x73\x88\xda\x80\x25', 'DTx', 18), # eth / DigitalTicks - (1, b'\x9c\x6f\xa4\x22\x09\x16\x9b\xce\xa0\x32\xe4\x01\x18\x8a\x6f\xc3\xe9\xc9\xf5\x9c', 'DUBI', 18), # eth / Decentralized Universal Basic Income - (1, b'\xd4\xcf\xfe\xef\x10\xf6\x0e\xca\x58\x1b\x5e\x11\x46\xb5\xac\xa4\x19\x4a\x4c\x3b', 'DUBI', 18), # eth / Decentralized Universal Basic Income - (1, b'\x99\x4f\x0d\xff\xdb\xae\x0b\xbf\x09\xb6\x52\xd6\xf1\x1a\x49\x3f\xd3\x3f\x42\xb9', 'EAGLE', 18), # eth / EagleCoin - (1, b'\xaf\xc3\x97\x88\xc5\x1f\x0c\x1f\xf7\xb5\x53\x17\xf3\xe7\x02\x99\xe5\x21\xff\xf6', 'eBCH', 8), # eth / eBCH - (1, b'\xeb\x7c\x20\x02\x71\x72\xe5\xd1\x43\xfb\x03\x0d\x50\xf9\x1c\xec\xe2\xd1\x48\x5d', 'eBTC', 8), # eth / eBTC - (1, b'\xa5\x78\xac\xc0\xcb\x78\x75\x78\x1b\x78\x80\x90\x3f\x45\x94\xd1\x3c\xfa\x8b\x98', 'ECN', 2), # eth / ECN - (1, b'\x17\xf9\x34\x75\xd2\xa9\x78\xf5\x27\xc3\xf7\xc4\x4a\xbf\x44\xad\xfb\xa6\x0d\x5c', 'ECO2', 2), # eth / EtherCO2 - (1, b'\xfa\x1d\xe2\xee\x97\xe4\xc1\x0c\x94\xc9\x1c\xb2\xb5\x06\x2b\x89\xfb\x14\x0b\x82', 'EDC', 6), # eth / Education Credits - (1, b'\x08\x71\x1d\x3b\x02\xc8\x75\x8f\x2f\xb3\xab\x4e\x80\x22\x84\x18\xa7\xf8\xe3\x9c', 'EDG', 0), # eth / Edgeless - (1, b'\xce\xd4\xe9\x31\x98\x73\x4d\xda\xff\x84\x92\xd5\x25\xbd\x25\x8d\x49\xeb\x38\x8e', 'EDO', 18), # eth / Eidoo - (1, b'\x5b\x26\xc5\xd0\x77\x2e\x5b\xba\xc8\xb3\x18\x2a\xe9\xa1\x3f\x9b\xb2\xd0\x37\x65', 'EDU', 8), # eth / EDU - (1, b'\x2a\x22\xe5\xcc\xa0\x0a\x3d\x63\x30\x8f\xa3\x9f\x29\x20\x2e\xb1\xb3\x9e\xef\x52', 'EDU', 6), # eth / EDU Token - (1, b'\xb5\x3a\x96\xbc\xbd\xd9\xcf\x78\xdf\xf2\x0b\xab\x6c\x2b\xe7\xba\xec\x8f\x00\xf8', 'eGAS', 8), # eth / ETH GAS - (1, b'\x8e\x1b\x44\x8e\xc7\xad\xfc\x7f\xa3\x5f\xc2\xe8\x85\x67\x8b\xd3\x23\x17\x6e\x34', 'EGT', 18), # eth / Egretia Token - (1, b'\xf9\xf0\xfc\x71\x67\xc3\x11\xdd\x2f\x1e\x21\xe9\x20\x4f\x87\xeb\xa9\x01\x2f\xb2', 'EHT', 8), # eth / EasyHomes - (1, b'\xbf\x21\x79\x85\x9f\xc6\xd5\xbe\xe9\xbf\x91\x58\x63\x2d\xc5\x16\x78\xa4\x10\x0e', 'ELF', 18), # eth / ELF Token - (1, b'\xc8\xc6\xa3\x1a\x4a\x80\x6d\x37\x10\xa7\xb3\x8b\x7b\x29\x6d\x2f\xab\xcc\xdb\xa8', 'ELIX', 18), # eth / Elixir Token - (1, b'\x44\x19\x7a\x4c\x44\xd6\xa0\x59\x29\x7c\xaf\x6b\xe4\xf7\xe1\x72\xbd\x56\xca\xaf', 'ELTCOIN', 8), # eth / ELTCOIN - (1, b'\xb6\x7b\x88\xa2\x57\x08\xa3\x5a\xe7\xc2\xd7\x36\xd3\x98\xd2\x68\xce\x4f\x7f\x83', 'EMON', 8), # eth / Etheremon - (1, b'\x95\xda\xaa\xb9\x80\x46\x84\x6b\xf4\xb2\x85\x3e\x23\xcb\xa2\x36\xfa\x39\x4a\x31', 'EMONT', 8), # eth / Etheremon Token - (1, b'\x95\x01\xbf\xc4\x88\x97\xdc\xee\xad\xf7\x31\x13\xef\x63\x5d\x2f\xf7\xee\x4b\x97', 'EMT', 18), # eth / easyMINE Token - (1, b'\xb8\x02\xb2\x4e\x06\x37\xc2\xb8\x7d\x2e\x8b\x77\x84\xc0\x55\xbb\xe9\x21\x01\x1a', 'EMV', 2), # eth / EMovieVenture - (1, b'\x03\x9f\x50\x50\xde\x49\x08\xf9\xb5\xdd\xf4\x0a\x4f\x3a\xa3\xf3\x29\x08\x63\x87', 'ENC', 18), # eth / Ethernet.Cash - (1, b'\xf0\xee\x6b\x27\xb7\x59\xc9\x89\x3c\xe4\xf0\x94\xb4\x9a\xd2\x8f\xd1\x5a\x23\xe4', 'ENG', 8), # eth / Enigma - (1, b'\xf6\x29\xcb\xd9\x4d\x37\x91\xc9\x25\x01\x52\xbd\x8d\xfb\xdf\x38\x0e\x2a\x3b\x9c', 'ENJ', 18), # eth / ENJIN - (1, b'\x5b\xc7\xe5\xf0\xab\x8b\x2e\x10\xd2\xd0\xa3\xf2\x17\x39\xfc\xe6\x24\x59\xae\xf3', 'ENTRP', 18), # eth / Hut34 Entropy Token - (1, b'\x86\xfa\x04\x98\x57\xe0\x20\x9a\xa7\xd9\xe6\x16\xf7\xeb\x3b\x3b\x78\xec\xfd\xb0', 'EOS', 18), # eth / EOS - (1, b'\x7e\x9e\x43\x1a\x0b\x8c\x4d\x53\x2c\x74\x5b\x10\x43\xc7\xfa\x29\xa4\x8d\x4f\xba', 'eosDAC', 18), # eth / eosDAC - (1, b'\x35\xba\xa7\x20\x38\xf1\x27\xf9\xf8\xc8\xf9\xb4\x91\x04\x9f\x64\xf3\x77\x91\x4d', 'EPX', 4), # eth / ethPoker.io EPX - (1, b'\xe8\xa1\xdf\x95\x8b\xe3\x79\x04\x5e\x2b\x46\xa3\x1a\x98\xb9\x3a\x2e\xcd\xfd\xed', 'ESZ', 18), # eth / ESZCoin - (1, b'\x1b\x97\x43\xf5\x56\xd6\x5e\x75\x7c\x4c\x65\x0b\x45\x55\xba\xf3\x54\xcb\x8b\xd3', 'ETBS', 12), # eth / Ethbits - (1, b'\xdd\x74\xa7\xa3\x76\x9f\xa7\x25\x61\xb3\xa6\x9e\x65\x96\x8f\x49\x74\x8c\x69\x0c', 'ETCH', 18), # eth / ETCH - (1, b'\x3a\x26\x74\x6d\xdb\x79\xb1\xb8\xe4\x45\x0e\x3f\x4f\xfe\x32\x85\xa3\x07\x38\x7e', 'ETHB', 8), # eth / EtherBTC - (1, b'\x69\x27\xc6\x9f\xb4\xda\xf2\x04\x3f\xbb\x1c\xb7\xb8\x6c\x56\x61\x41\x6b\xea\x29', 'ETR', 18), # eth / Etheruem Risen - (1, b'\xab\xdf\x14\x78\x70\x23\x5f\xcf\xc3\x41\x53\x82\x8c\x76\x9a\x70\xb3\xfa\xe0\x1f', 'EURT', 6), # eth / EUR Tether (erc20) - (1, b'\x52\x36\x30\x97\x6e\xb6\x14\x76\x21\xb5\xc3\x1c\x78\x1e\xbe\x2e\xc2\xa8\x06\xe0', 'eUSD', 18), # eth / Ether-Backed USD Nomins (erc20) - (1, b'\x92\x31\x08\xa4\x39\xc4\xe8\xc2\x31\x5c\x4f\x65\x21\xe5\xce\x95\xb4\x4e\x9b\x4c', 'EVE', 18), # eth / EVE - (1, b'\xd7\x80\xae\x2b\xf0\x4c\xd9\x6e\x57\x7d\x3d\x01\x47\x62\xf8\x31\xd9\x71\x29\xd0', 'EVN', 18), # eth / Envion AG - (1, b'\xf3\xdb\x5f\xa2\xc6\x6b\x7a\xf3\xeb\x0c\x0b\x78\x25\x10\x81\x6c\xbe\x48\x13\xb8', 'EVX', 4), # eth / EVX Token - (1, b'\xc9\x8e\x06\x39\xc6\xd2\xec\x03\x7a\x61\x53\x41\xc3\x69\x66\x6b\x11\x0e\x80\xe5', 'EXMR', 8), # eth / eXMRcoin - (1, b'\x19\x0e\x56\x9b\xe0\x71\xf4\x0c\x70\x4e\x15\x82\x5f\x28\x54\x81\xcb\x74\xb6\xcc', 'FAM', 12), # eth / FAM - (1, b'\x7f\x67\x15\xc3\xfc\x47\x40\xa0\x2f\x70\xde\x85\xb9\xfd\x50\xac\x60\x01\xfe\xd9', 'FANX', 18), # eth / FANX Token - (1, b'\x00\x9e\x86\x49\x23\xb4\x92\x63\xc7\xf1\x0d\x19\xb7\xf8\xab\x7a\x9a\x5a\xad\x33', 'FKX', 18), # eth / Knoxstertoken - (1, b'\xf0\x4a\x8a\xc5\x53\xfc\xed\xb5\xba\x99\xa6\x47\x99\x15\x58\x26\xc1\x36\xb0\xbe', 'FLIXX', 18), # eth / FLIXX - (1, b'\x04\xcc\x78\x3b\x45\x0b\x8d\x11\xf3\xc7\xd0\x0d\xd0\x3f\xdf\x7f\xb5\x1f\xe9\xf2', 'FLMC', 18), # eth / Filmscoin - (1, b'\x59\x76\xf7\xda\xc1\x52\x5e\xf3\x27\x78\x36\x04\x3b\xa4\x74\xa3\x5e\x6b\x42\x72', 'FLMC', 0), # eth / Filmscoin - (1, b'\x3a\x1b\xda\x28\xad\xb5\xb0\xa8\x12\xa7\xcf\x10\xa1\x95\x0c\x92\x0f\x79\xbc\xd3', 'FLP', 18), # eth / FLIP Token - (1, b'\x9a\xef\xbe\x0b\x3c\x3b\xa9\xea\xb2\x62\xcb\x98\x56\xe8\x15\x7a\xb7\x64\x8e\x09', 'FLR', 18), # eth / Flair Coin - (1, b'\x95\x4b\x5d\xe0\x9a\x55\xe5\x97\x55\xac\xbd\xa2\x9e\x1e\xb7\x4a\x45\xd3\x01\x75', 'FLUZ', 18), # eth / Fluz Fluz Global - (1, b'\x70\xb1\x47\xe0\x1e\x92\x85\xe7\xce\x68\xb9\xba\x43\x7f\xe3\xa9\x19\x0e\x75\x6a', 'FLX', 18), # eth / BitFlux - (1, b'\x4d\xf4\x7b\x49\x69\xb2\x91\x1c\x96\x65\x06\xe3\x59\x2c\x41\x38\x94\x93\x95\x3b', 'FND', 18), # eth / FundRequest - (1, b'\x0a\xbe\xfb\x76\x11\xcb\x3a\x01\xea\x3f\xad\x85\xf3\x3c\x3c\x93\x4f\x8e\x2c\xf4', 'FRD', 18), # eth / FARAD Cryptoken - (1, b'\xe6\xf7\x4d\xcf\xa0\xe2\x08\x83\x00\x8d\x8c\x16\xb6\xd9\xa3\x29\x18\x9d\x0c\x30', 'FTC', 2), # eth / FTC - (1, b'\x20\x23\xdc\xf7\xc4\x38\xc8\xc8\xc0\xb0\xf2\x8d\xba\xe1\x55\x20\xb4\xf3\xee\x20', 'FTR', 18), # eth / Futourist Token - (1, b'\x2a\xec\x18\xc5\x50\x0f\x21\x35\x9c\xe1\xbe\xa5\xdc\x17\x77\x34\x4d\xf4\xc0\xdc', 'FTT', 18), # eth / FarmaTrust Token - (1, b'\x65\xbe\x44\xc7\x47\x98\x8f\xbf\x60\x62\x07\x69\x8c\x94\x4d\xf4\x44\x2e\xfe\x19', 'FUCK', 4), # eth / Finally Usable Crypto Karma - (1, b'\xab\x16\xe0\xd2\x5c\x06\xcb\x37\x62\x59\xcc\x18\xc1\xde\x4a\xca\x57\x60\x55\x89', 'FUCK', 4), # eth / FinallyUsableCryptoKarma - (1, b'\xea\x38\xea\xa3\xc8\x6c\x8f\x9b\x75\x15\x33\xba\x2e\x56\x2d\xeb\x9a\xcd\xed\x40', 'FUEL', 18), # eth / Etherparty FUEL - (1, b'\x41\x9d\x0d\x8b\xdd\x9a\xf5\xe6\x06\xae\x22\x32\xed\x28\x5a\xff\x19\x0e\x71\x1b', 'FUN', 8), # eth / Funfair - (1, b'\x88\xfc\xfb\xc2\x2c\x6d\x3d\xba\xa2\x5a\xf4\x78\xc5\x78\x97\x83\x39\xbd\xe7\x7a', 'FYN', 18), # eth / Fund Yourself Now - (1, b'\xf6\x74\x51\xdc\x84\x21\xf0\xe0\xaf\xeb\x52\xfa\xa8\x10\x10\x34\xed\x08\x1e\xd9', 'GAM', 8), # eth / Gambit - (1, b'\x67\x54\xe2\x1b\x9e\xaa\x05\x3c\x62\xd7\x85\x4d\xd6\x56\x1a\xe4\x51\xb0\xcb\xcf', 'GANA', 18), # eth / GANA - (1, b'\xc0\xea\x63\x06\xf6\x36\x0f\xe7\xdc\xab\x65\xd1\x6b\xf1\xa3\xaf\x92\xc7\x9a\xa2', 'GANA', 18), # eth / GANA - (1, b'\x70\x88\x76\xf4\x86\xe4\x48\xee\x89\xeb\x33\x2b\xfb\xc8\xe5\x93\x55\x30\x58\xb9', 'GAVEL', 18), # eth / GAVEL - (1, b'\x75\x85\xf8\x35\xae\x2d\x52\x27\x22\xd2\x68\x43\x23\xa0\xba\x83\x40\x1f\x32\xf5', 'GBT', 18), # eth / GBT - (1, b'\x12\xfc\xd6\x46\x3e\x66\x97\x4c\xf7\xbb\xc2\x4f\xfc\x4d\x40\xd6\xbe\x45\x82\x83', 'GBX', 18), # eth / Globitex - (1, b'\xdb\x0f\x69\x30\x6f\xf8\xf9\x49\xf2\x58\xe8\x3f\x6b\x87\xee\x5d\x05\x2d\x0b\x23', 'GCP', 18), # eth / Globcoin Crypto Platform - (1, b'\x4f\x4f\x0d\xb4\xde\x90\x3b\x88\xf2\xb1\xa2\x84\x79\x71\xe2\x31\xd5\x4f\x8f\xd3', 'GEE', 8), # eth / Geens NPO - (1, b'\x24\x08\x3b\xb3\x00\x72\x64\x3c\x3b\xb9\x0b\x44\xb7\x28\x58\x60\xa7\x55\xe6\x87', 'GELD', 18), # eth / GELD - (1, b'\x54\x3f\xf2\x27\xf6\x4a\xa1\x7e\xa1\x32\xbf\x98\x86\xca\xb5\xdb\x55\xdc\xad\xdf', 'GEN', 18), # eth / DAOstack - (1, b'\x8a\x85\x42\x88\xa5\x97\x60\x36\xa7\x25\x87\x91\x64\xca\x3e\x91\xd3\x0c\x6a\x1b', 'GET', 18), # eth / GET - (1, b'\xfc\xd8\x62\x98\x56\x28\xb2\x54\x06\x1f\x7a\x91\x80\x35\xb8\x03\x40\xd0\x45\xd3', 'GIF', 18), # eth / GIFcoin Token - (1, b'\xae\x4f\x56\xf0\x72\xc3\x4c\x0a\x65\xb3\xae\x3e\x4d\xb7\x97\xd8\x31\x43\x9d\x93', 'GIM', 8), # eth / Gimli - (1, b'\xb3\xbd\x49\xe2\x8f\x8f\x83\x2b\x8d\x1e\x24\x61\x06\x99\x1e\x54\x6c\x32\x35\x02', 'GMT', 18), # eth / GMT - (1, b'\x68\x10\xe7\x76\x88\x0c\x02\x93\x3d\x47\xdb\x1b\x9f\xc0\x59\x08\xe5\x38\x6b\x96', 'GNO', 18), # eth / Gnosis - (1, b'\xa7\x44\x76\x44\x31\x19\xa9\x42\xde\x49\x85\x90\xfe\x1f\x24\x54\xd7\xd4\xac\x0d', 'GNT', 18), # eth / Golem - (1, b'\xea\xb4\x31\x93\xcf\x06\x23\x07\x3c\xa8\x9d\xb9\xb7\x12\x79\x63\x56\xfa\x74\x14', 'GOLDX', 18), # eth / GOLDX - (1, b'\x12\xb1\x9d\x3e\x2c\xcc\x14\xda\x04\xfa\xe3\x3e\x63\x65\x2c\xe4\x69\xb3\xf2\xfd', 'GRID', 12), # eth / GRID - (1, b'\x0a\x9a\x9c\xe6\x00\xd0\x8b\xf9\xb7\x6f\x49\xfa\x4e\x7b\x38\xa6\x7e\xbe\xb1\xe6', 'GROW', 8), # eth / Growchain - (1, b'\xb7\x08\x35\xd7\x82\x2e\xbb\x94\x26\xb5\x65\x43\xe3\x91\x84\x6c\x10\x7b\xd3\x2c', 'GTC', 18), # eth / GTC Token - (1, b'\x02\x5a\xba\xd9\xe5\x18\x51\x6f\xda\xaf\xbd\xcd\xb9\x70\x1b\x37\xfb\x7e\xf0\xfa', 'GTKT', 0), # eth / GTKT - (1, b'\xc5\xbb\xae\x50\x78\x1b\xe1\x66\x93\x06\xb9\xe0\x01\xef\xf5\x7a\x29\x57\xb0\x9d', 'GTO', 5), # eth / Gifto - (1, b'\xf7\xb0\x98\x29\x8f\x7c\x69\xfc\x14\x61\x0b\xf7\x1d\x5e\x02\xc6\x07\x92\x89\x4c', 'GUP', 3), # eth / GUP - (1, b'\x10\x3c\x3a\x20\x9d\xa5\x9d\x3e\x7c\x4a\x89\x30\x7e\x66\x52\x1e\x08\x1c\xfd\xf0', 'GVT', 18), # eth / Genesis Vision - (1, b'\x58\xca\x30\x65\xc0\xf2\x4c\x7c\x96\xae\xe8\xd6\x05\x6b\x5b\x5d\xec\xf9\xc2\xf8', 'GXC', 10), # eth / GXC - (1, b'\x22\xf0\xaf\x8d\x78\x85\x1b\x72\xee\x79\x9e\x05\xf5\x4a\x77\x00\x15\x86\xb1\x8a', 'GXVC', 10), # eth / Genevieve VC - (1, b'\x8c\x65\xe9\x92\x29\x7d\x5f\x09\x2a\x75\x6d\xef\x24\xf4\x78\x1a\x28\x01\x98\xff', 'GZE', 18), # eth / GazeCoin - (1, b'\xe6\x38\xdc\x39\xb6\xad\xbe\xe8\x52\x6b\x5c\x22\x38\x0b\x4b\x45\xda\xf4\x6d\x8e', 'GZR', 6), # eth / Gizer - (1, b'\x90\x02\xd4\x48\x5b\x75\x94\xe3\xe8\x50\xf0\xa2\x06\x71\x3b\x30\x51\x13\xf6\x9e', 'HAT', 18), # eth / Hawala Today - (1, b'\xc0\x11\xa7\x24\x00\xe5\x8e\xcd\x99\xee\x49\x7c\xf8\x9e\x37\x75\xd4\xbd\x73\x2f', 'HAV', 18), # eth / Havven - (1, b'\xff\xe8\x19\x6b\xc2\x59\xe8\xde\xdc\x54\x4d\x93\x57\x86\xaa\x47\x09\xec\x3e\x64', 'HDG', 18), # eth / Hedge Crypto - (1, b'\xe9\xff\x07\x80\x9c\xcf\xf0\x5d\xae\x74\x99\x0e\x25\x83\x1d\x0b\xc5\xcb\xe5\x75', 'Hdp', 18), # eth / HEdpAY - (1, b'\xba\x21\x84\x52\x0a\x1c\xc4\x9a\x61\x59\xc5\x7e\x61\xe1\x84\x4e\x08\x56\x15\xb6', 'HGT', 8), # eth / HGT - (1, b'\xa9\x24\x0f\xbc\xac\x1f\x0b\x9a\x6a\xdf\xb0\x4a\x53\xc8\xe3\xb0\xcc\x1d\x14\x44', 'HIG', 18), # eth / ethereumhigh - (1, b'\x14\xf3\x7b\x57\x42\x42\xd3\x66\x55\x8d\xb6\x1f\x33\x35\x28\x9a\x50\x35\xc5\x06', 'HKG', 3), # eth / HKG - (1, b'\x88\xac\x94\xd5\xd1\x75\x13\x03\x47\xfc\x95\xe1\x09\xd7\x7a\xc0\x9d\xbf\x5a\xb7', 'HKY', 18), # eth / Hicky - (1, b'\xcb\xcc\x0f\x03\x6e\xd4\x78\x8f\x63\xfc\x0f\xee\x32\x87\x3d\x6a\x74\x87\xb9\x08', 'HMQ', 8), # eth / HMQ - (1, b'\xb4\x5d\x7b\xc4\xce\xbc\xab\x98\xad\x09\xba\xbd\xf8\xc8\x18\xb2\x29\x2b\x67\x2c', 'HODL', 18), # eth / HODLCoin - (1, b'\x5b\x07\x51\x71\x3b\x25\x27\xd7\xf0\x02\xc0\xc4\xe2\xa3\x7e\x12\x19\x61\x0a\x6b', 'HORSE', 18), # eth / HORSE - (1, b'\x6c\x6e\xe5\xe3\x1d\x82\x8d\xe2\x41\x28\x2b\x96\x06\xc8\xe9\x8e\xa4\x85\x26\xe2', 'HOT', 18), # eth / HoloToken - (1, b'\x9a\xf8\x39\x68\x7f\x6c\x94\x54\x2a\xc5\xec\xe2\xe3\x17\xda\xae\x35\x54\x93\xa1', 'HOT', 18), # eth / Hydro Protocol - (1, b'\x55\x4c\x20\xb7\xc4\x86\xbe\xee\x43\x92\x77\xb4\x54\x0a\x43\x45\x66\xdc\x4c\x02', 'HST', 18), # eth / HST - (1, b'\xc0\xeb\x85\x28\x5d\x83\x21\x7c\xd7\xc8\x91\x70\x2b\xcb\xc0\xfc\x40\x1e\x2d\x9d', 'HVN', 8), # eth / Hive Project - (1, b'\xeb\xbd\xf3\x02\xc9\x40\xc6\xbf\xd4\x9c\x6b\x16\x5f\x45\x7f\xdb\x32\x46\x49\xbc', 'HYDRO', 18), # eth / Hydro - (1, b'\xc1\xe2\x09\x7d\x78\x8d\x33\x70\x1b\xa3\xcc\x27\x73\xbf\x67\x15\x5e\xc9\x3f\xc4', 'IAD', 18), # eth / IADOWR Coin - (1, b'\x5a\x84\x96\x9b\xb6\x63\xfb\x64\xf6\xd0\x15\xdc\xf9\xf6\x22\xae\xdc\x79\x67\x50', 'ICE', 18), # eth / ICE - (1, b'\x88\x86\x66\xca\x69\xe0\xf1\x78\xde\xd6\xd7\x5b\x57\x26\xce\xe9\x9a\x87\xd6\x98', 'ICN', 18), # eth / ICN - (1, b'\xa3\x3e\x72\x9b\xf4\xfd\xeb\x86\x8b\x53\x4e\x1f\x20\x52\x34\x63\xd9\xc4\x6b\xee', 'ICO', 10), # eth / ICO - (1, b'\x01\x4b\x50\x46\x65\x90\x34\x0d\x41\x30\x7c\xc5\x4d\xce\xe9\x90\xc8\xd5\x8a\xa8', 'ICOS', 6), # eth / ICOS - (1, b'\xb5\xa5\xf2\x26\x94\x35\x2c\x15\xb0\x03\x23\x84\x4a\xd5\x45\xab\xb2\xb1\x10\x28', 'ICX', 18), # eth / ICON - (1, b'\x81\x4c\xaf\xd4\x78\x2d\x2e\x72\x81\x70\xfd\xa6\x82\x57\x98\x3f\x03\x32\x1c\x58', 'IDEA', 0), # eth / IDEA Token - (1, b'\x76\x54\x91\x5a\x1b\x82\xd6\xd2\xd0\xaf\xc3\x7c\x52\xaf\x55\x6e\xa8\x98\x3c\x7e', 'IFT', 18), # eth / InvestFeed - (1, b'\x16\x66\x2f\x73\xdf\x3e\x79\xe5\x4c\x6c\x59\x38\xb4\x31\x3f\x92\xc5\x24\xc1\x20', 'IIC', 18), # eth / IIC - (1, b'\x88\xae\x96\x84\x5e\x15\x75\x58\xef\x59\xe9\xff\x90\xe7\x66\xe2\x2e\x48\x03\x90', 'IKB', 0), # eth / IKB - (1, b'\xe3\x83\x1c\x5a\x98\x2b\x27\x9a\x19\x84\x56\xd5\x77\xcf\xb9\x04\x24\xcb\x63\x40', 'IMC', 6), # eth / Immune Coin - (1, b'\x22\xe5\xf6\x2d\x0f\xa1\x99\x74\x74\x9f\xaa\x19\x4e\x3d\x3e\xf6\xd8\x9c\x08\xd7', 'IMT', 0), # eth / IMT - (1, b'\xf8\xe3\x86\xed\xa8\x57\x48\x4f\x5a\x12\xe4\xb5\xda\xa9\x98\x4e\x06\xe7\x37\x05', 'IND', 18), # eth / Indorse - (1, b'\x48\xe5\x41\x3b\x73\xad\xd2\x43\x4e\x47\x50\x4e\x2a\x22\xd1\x49\x40\xdb\xfe\x78', 'INRM', 3), # eth / Integrated Money - (1, b'\x5b\x2e\x4a\x70\x0d\xfb\xc5\x60\x06\x1e\x95\x7e\xde\xc8\xf6\xee\xeb\x74\xa3\x20', 'INS', 10), # eth / INS - (1, b'\xc7\x2f\xe8\xe3\xdd\x5b\xef\x0f\x9f\x31\xf2\x59\x39\x9f\x30\x12\x72\xef\x2a\x2d', 'INSTAR', 18), # eth / Insights Network - (1, b'\xa8\x00\x6c\x4c\xa5\x6f\x24\xd6\x83\x67\x27\xd1\x06\x34\x93\x20\xdb\x7f\xef\x82', 'INXT', 8), # eth / Internxt - (1, b'\xfa\x1a\x85\x6c\xfa\x34\x09\xcf\xa1\x45\xfa\x4e\x20\xeb\x27\x0d\xf3\xeb\x21\xab', 'IOST', 18), # eth / IOSToken - (1, b'\xc3\x4b\x21\xf6\xf8\xe5\x1c\xc9\x65\xc2\x39\x3b\x3c\xcf\xa3\xb8\x2b\xeb\x24\x03', 'IoT', 6), # eth / IoTコイン - (1, b'\x6f\xb3\xe0\xa2\x17\x40\x7e\xff\xf7\xca\x06\x2d\x46\xc2\x6e\x5d\x60\xa1\x4d\x69', 'IOTX', 18), # eth / IoTeX Network - (1, b'\x64\xcd\xf8\x19\xd3\xe7\x5a\xc8\xec\x21\x7b\x34\x96\xd7\xce\x16\x7b\xe4\x2e\x80', 'IPL', 18), # eth / InsurePal token - (1, b'\x00\x1f\x0a\xa5\xda\x15\x58\x5e\x5b\x23\x05\xdb\xab\x2b\xac\x42\x5e\xa7\x10\x07', 'IPSX', 18), # eth / IPSX - (1, b'\x5e\x6b\x6d\x9a\xba\xd9\x09\x3f\xdc\x86\x1e\xa1\x60\x0e\xba\x1b\x35\x5c\xd9\x40', 'ITC', 18), # eth / IoT Chain - (1, b'\x0a\xef\x06\xdc\xcc\xc5\x31\xe5\x81\xf0\x44\x00\x59\xe6\xff\xcc\x20\x60\x39\xee', 'ITT', 8), # eth / ITT Token - (1, b'\xfc\xa4\x79\x62\xd4\x5a\xdf\xdf\xd1\xab\x2d\x97\x23\x15\xdb\x4c\xe7\xcc\xf0\x94', 'IXT', 8), # eth / InsureX - (1, b'\x0d\x26\x2e\x5d\xc4\xa0\x6a\x0f\x1c\x90\xce\x79\xc7\xa6\x0c\x09\xdf\xc8\x84\xe4', 'J8T', 8), # eth / J8T Token - (1, b'\x0a\xaf\x56\x1e\xff\x5b\xd9\xc8\xf9\x11\x61\x69\x33\xf8\x41\x66\xa1\x7c\xfe\x0c', 'JBX', 0), # eth / JBX - (1, b'\x88\x4e\x39\x02\xc4\xd5\xcf\xa8\x6d\xe4\xac\xe7\xa9\x6a\xa9\x1e\xbc\x25\xc0\xff', 'JBX', 18), # eth / JBOX - (1, b'\x87\x27\xc1\x12\xc7\x12\xc4\xa0\x33\x71\xac\x87\xa7\x4d\xd6\xab\x10\x4a\xf7\x68', 'JET', 18), # eth / JET - (1, b'\x77\x34\x50\x33\x5e\xd4\xec\x3d\xb4\x5a\xf7\x4f\x34\xf2\xc8\x53\x48\x64\x5d\x39', 'JetCoins', 18), # eth / JetCoins - (1, b'\xa5\xfd\x1a\x79\x1c\x4d\xfc\xaa\xcc\x96\x3d\x4f\x73\xc6\xae\x58\x24\x14\x9e\xa7', 'JNT', 18), # eth / JNT - (1, b'\xdd\xe1\x2a\x12\xa6\xf6\x71\x56\xe0\xda\x67\x2b\xe0\x5c\x37\x4e\x1b\x0a\x3e\x57', 'JOY', 6), # eth / JOYSO - (1, b'\x0d\x6d\xd9\xf6\x8d\x24\xec\x1d\x5f\xe2\x17\x4f\x3e\xc8\xda\xb5\x2b\x52\xba\xf5', 'KC', 18), # eth / KMCC - (1, b'\x72\xd3\x2a\xc1\xc5\xe6\x6b\xfc\x5b\x08\x80\x62\x71\xf8\xee\xf9\x15\x54\x51\x64', 'KEE', 0), # eth / CryptoKEE - (1, b'\x4c\xc1\x93\x56\xf2\xd3\x73\x38\xb9\x80\x2a\xa8\xe8\xfc\x58\xb0\x37\x32\x96\xe7', 'KEY', 18), # eth / SelfKey - (1, b'\x4c\xd9\x88\xaf\xba\xd3\x72\x89\xba\xaf\x53\xc1\x3e\x98\xe2\xbd\x46\xaa\xea\x8c', 'KEY', 18), # eth / BihuKey - (1, b'\x27\x69\x5e\x09\x14\x9a\xdc\x73\x8a\x97\x8e\x9a\x67\x8f\x99\xe4\xc3\x9e\x9e\xb9', 'KICK', 8), # eth / KICK - (1, b'\x81\x8f\xc6\xc2\xec\x59\x86\xbc\x6e\x2c\xbf\x00\x93\x9d\x90\x55\x6a\xb1\x2c\xe5', 'KIN', 18), # eth / Kin Foundation - (1, b'\xdd\x97\x4d\x5c\x2e\x29\x28\xde\xa5\xf7\x1b\x98\x25\xb8\xb6\x46\x68\x6b\xd2\x00', 'KNC', 18), # eth / Kyber Network - (1, b'\xb5\xc3\x3f\x96\x5c\x88\x99\xd2\x55\xc3\x4c\xdd\x2a\x3e\xfa\x8a\xbc\xbb\x3d\xea', 'KPR', 18), # eth / KPRCoin - (1, b'\x46\x4e\xbe\x77\xc2\x93\xe4\x73\xb4\x8c\xfe\x96\xdd\xcf\x88\xfc\xf7\xbf\xda\xc0', 'KRL', 18), # eth / Kryll - (1, b'\x95\x41\xfd\x8b\x9b\x5f\xa9\x73\x81\x78\x37\x83\xce\xbf\x2f\x5f\xa7\x93\xc2\x62', 'KZN', 8), # eth / KaizenCoin - (1, b'\xe5\x03\x65\xf5\xd6\x79\xcb\x98\xa1\xdd\x62\xd6\xf6\xe5\x8e\x59\x32\x1b\xcd\xdf', 'LA', 18), # eth / LATOKEN - (1, b'\xfd\x10\x7b\x47\x3a\xb9\x0e\x8f\xbd\x89\x87\x21\x44\xa3\xdc\x92\xc4\x0f\xa8\xc9', 'LALA', 18), # eth / LALA World Token - (1, b'\x51\x02\x79\x1c\xa0\x2f\xc3\x59\x53\x98\x40\x0b\xfe\x0e\x33\xd7\xb6\xc8\x22\x67', 'LDC', 18), # eth / LEADCOIN - (1, b'\xd6\xe3\x54\xf0\x73\x19\xe2\x47\x44\x91\xd8\xc7\xc7\x12\x13\x7b\xee\x68\x62\xa2', 'LEMO', 0), # eth / Lemo - (1, b'\xb5\xae\x84\x8e\xdb\x29\x6c\x21\x25\x9b\x74\x67\x33\x14\x67\xd2\x64\x7e\xec\xdf', 'LEMO', 18), # eth / Lemo - (1, b'\x80\xfb\x78\x4b\x7e\xd6\x67\x30\xe8\xb1\xdb\xd9\x82\x0a\xfd\x29\x93\x1a\xab\x03', 'LEND', 18), # eth / EHTLend - (1, b'\xc7\x98\xcd\x1c\x49\xdb\x0e\x29\x73\x12\xe4\xc6\x82\x75\x26\x68\xce\x1d\xb2\xad', 'LFR', 5), # eth / LifeRun Coin - (1, b'\x12\x3a\xb1\x95\xdd\x38\xb1\xb4\x05\x10\xd4\x67\xa6\xa3\x59\xb2\x01\xaf\x05\x6f', 'LGO', 8), # eth / LGO - (1, b'\x2e\xb8\x6e\x8f\xc5\x20\xe0\xf6\xbb\x5d\x9a\xf0\x8f\x92\x4f\xe7\x05\x58\xab\x89', 'LGR', 8), # eth / Logarithm - (1, b'\xeb\x99\x51\x02\x16\x98\xb4\x2e\x43\x99\xf9\xcb\xb6\x26\x7a\xa3\x5f\x82\xd5\x9d', 'LIF', 18), # eth / LIF - (1, b'\xff\x18\xdb\xc4\x87\xb4\xc2\xe3\x22\x2d\x11\x59\x52\xba\xbf\xda\x8b\xa5\x2f\x5f', 'LIFE', 18), # eth / LIFE - (1, b'\x51\x49\x10\x77\x1a\xf9\xca\x65\x6a\xf8\x40\xdf\xf8\x3e\x82\x64\xec\xf9\x86\xca', 'LINK (Chainlink)', 18), # eth / LINK Chainlink - (1, b'\xe2\xe6\xd4\xbe\x08\x6c\x69\x38\xb5\x3b\x22\x14\x48\x55\xee\xf6\x74\x28\x16\x39', 'LINK Platform', 18), # eth / Link Platform - (1, b'\x24\xa7\x7c\x1f\x17\xc5\x47\x10\x5e\x14\x81\x3e\x51\x7b\xe0\x6b\x00\x40\xaa\x76', 'LIVE', 18), # eth / LIVE Token - (1, b'\x63\xe6\x34\x33\x0a\x20\x15\x0d\xbb\x61\xb1\x56\x48\xbc\x73\x85\x5d\x6c\xcf\x07', 'LNC', 18), # eth / Lancer Token - (1, b'\x6b\xeb\x41\x8f\xc6\xe1\x95\x82\x04\xac\x8b\xad\xdc\xf1\x09\xb8\xe9\x69\x49\x66', 'LNC-Linker Coin', 18), # eth / Linker Coin - (1, b'\x09\x47\xb0\xe6\xd8\x21\x37\x88\x05\xc9\x59\x82\x91\x38\x5c\xe7\xc7\x91\xa6\xb2', 'LND', 18), # eth / Lendingblock - (1, b'\x5e\x33\x46\x44\x40\x10\x13\x53\x22\x26\x8a\x46\x30\xd2\xed\x5f\x8d\x09\x44\x6c', 'LOC', 18), # eth / LockChain - (1, b'\x9c\x23\xd6\x7a\xea\x7b\x95\xd8\x09\x42\xe3\x83\x6b\xcd\xf7\xe7\x08\xa7\x47\xc2', 'LOCI', 18), # eth / LOCIcoin - (1, b'\xc6\x45\x00\xdd\x7b\x0f\x17\x94\x80\x7e\x67\x80\x2f\x8a\xbb\xf5\xf8\xff\xb0\x54', 'LOCUS', 18), # eth / Locus Chain - (1, b'\x21\xae\x23\xb8\x82\xa3\x40\xa2\x22\x82\x16\x20\x86\xbc\x98\xd3\xe2\xb7\x30\x18', 'LOK', 18), # eth / LOK - (1, b'\xa4\xe8\xc3\xec\x45\x61\x07\xea\x67\xd3\x07\x5b\xf9\xe3\xdf\x3a\x75\x82\x3d\xb0', 'LOOM', 18), # eth / LOOM - (1, b'\x58\xb6\xa8\xa3\x30\x23\x69\xda\xec\x38\x33\x34\x67\x24\x04\xee\x73\x3a\xb2\x39', 'LPT', 18), # eth / Livepeer Token - (1, b'\xef\x68\xe7\xc6\x94\xf4\x0c\x82\x02\x82\x1e\xdf\x52\x5d\xe3\x78\x24\x58\x63\x9f', 'LRC', 18), # eth / LRC - (1, b'\x5d\xbe\x29\x6f\x97\xb2\x3c\x4a\x6a\xa6\x18\x3d\x73\xe5\x74\xd0\x2b\xa5\xc7\x19', 'LUC', 18), # eth / LUCToken - (1, b'\xfb\x12\xe3\xcc\xa9\x83\xb9\xf5\x9d\x90\x91\x2f\xd1\x7f\x8d\x74\x5a\x8b\x29\x53', 'LUCK', 0), # eth / LUCK - (1, b'\xa8\x9b\x59\x34\x86\x34\x47\xf6\xe4\xfc\x53\xb3\x15\xa9\x3e\x87\x3b\xda\x69\xa3', 'LUM', 18), # eth / Lumino Coin - (1, b'\xfa\x05\xa7\x3f\xfe\x78\xef\x8f\x1a\x73\x94\x73\xe4\x62\xc5\x4b\xae\x65\x67\xd9', 'LUN', 18), # eth / LUN - (1, b'\xdd\x41\xfb\xd1\xae\x95\xc5\xd9\xb1\x98\x17\x4a\x28\xe0\x4b\xe6\xb3\xd1\xaa\x27', 'LYS', 8), # eth / Lightyears - (1, b'\x3f\x4b\x72\x66\x68\xda\x46\xf5\xe0\xe7\x5a\xa5\xd4\x78\xac\xec\x9f\x38\x21\x0f', 'M-ETH', 18), # eth / M-ETH - (1, b'\x5b\x09\xa0\x37\x1c\x1d\xa4\x4a\x8e\x24\xd3\x6b\xf5\xde\xb1\x14\x1a\x84\xd8\x75', 'MAD', 18), # eth / MAD - (1, b'\xe2\x5b\xce\xc5\xd3\x80\x1c\xe3\xa7\x94\x07\x9b\xf9\x4a\xdf\x1b\x8c\xcd\x80\x2d', 'MAN', 18), # eth / MAN - (1, b'\x0f\x5d\x2f\xb2\x9f\xb7\xd3\xcf\xee\x44\x4a\x20\x02\x98\xf4\x68\x90\x8c\xc9\x42', 'MANA', 18), # eth / Decentraland MANA - (1, b'\xfd\xcc\x07\xab\x60\x66\x0d\xe5\x33\xb5\xad\x26\xe1\x45\x7b\x56\x5a\x9d\x59\xbd', 'MART', 18), # eth / Martcoin - (1, b'\x38\x64\x67\xf1\xf3\xdd\xbe\x83\x24\x48\x65\x04\x18\x31\x1a\x47\x9e\xec\xfc\x57', 'MBRS', 0), # eth / Embers - (1, b'\x93\xe6\x82\x10\x7d\x1e\x9d\xef\xb0\xb5\xee\x70\x1c\x71\x70\x7a\x4b\x2e\x46\xbc', 'MCAP', 8), # eth / MCAP - (1, b'\x13\x8a\x87\x52\x09\x3f\x4f\x9a\x79\xaa\xed\xf4\x8d\x4b\x92\x48\xfa\xb9\x3c\x9c', 'MCI', 18), # eth / Musiconomi - (1, b'\xb6\x3b\x60\x6a\xc8\x10\xa5\x2c\xca\x15\xe4\x4b\xb6\x30\xfd\x42\xd8\xd1\xd8\x3d', 'MCO', 8), # eth / MCO - (1, b'\x51\xdb\x5a\xd3\x5c\x67\x1a\x87\x20\x7d\x88\xfc\x11\xd5\x93\xac\x0c\x84\x15\xbd', 'MDA', 18), # eth / MDA - (1, b'\x01\xf2\xac\xf2\x91\x48\x60\x33\x1c\x1c\xb1\xa9\xac\xec\xda\x74\x75\xe0\x6a\xf8', 'MESH', 18), # eth / Meshbox - (1, b'\x5b\x8d\x43\xff\xde\x4a\x29\x82\xb9\xa5\x38\x7c\xdf\x21\xd5\x4e\xad\x64\xac\x8d', 'MEST', 18), # eth / Monaco Estate - (1, b'\x67\x10\xc6\x34\x32\xa2\xde\x02\x95\x4f\xc0\xf8\x51\xdb\x07\x14\x6a\x6c\x03\x12', 'MFG', 18), # eth / SyncFab Smart Manufacturing Blockchain - (1, b'\x40\x39\x50\x44\xac\x3c\x0c\x57\x05\x19\x06\xda\x93\x8b\x54\xbd\x65\x57\xf2\x12', 'MGO', 8), # eth / MGO - (1, b'\xe2\x3c\xd1\x60\x76\x1f\x63\xfc\x3a\x1c\xf7\x8a\xa0\x34\xb6\xcd\xf9\x7d\x3e\x0c', 'MIT', 18), # eth / MIT - (1, b'\xad\x8d\xd4\xc7\x25\xde\x1d\x31\xb9\xe8\xf8\xd1\x46\x08\x9e\x9d\xc6\x88\x20\x93', 'MIT (Mychatcoin)', 6), # eth / Mychatcoin - (1, b'\x9f\x8f\x72\xaa\x93\x04\xc8\xb5\x93\xd5\x55\xf1\x2e\xf6\x58\x9c\xc3\xa5\x79\xa2', 'MKR', 18), # eth / MakerDAO - (1, b'\x79\x39\x88\x2b\x54\xfc\xf0\xbc\xae\x6b\x53\xde\xc3\x9a\xd6\xe8\x06\x17\x64\x42', 'MKT', 8), # eth / Mikado - (1, b'\xbe\xb9\xef\x51\x4a\x37\x9b\x99\x7e\x07\x98\xfd\xcc\x90\x1e\xe4\x74\xb6\xd9\xa1', 'MLN', 18), # eth / Melonport - (1, b'\x1a\x95\xb2\x71\xb0\x53\x5d\x15\xfa\x49\x93\x2d\xab\xa3\x1b\xa6\x12\xb5\x29\x46', 'MNE', 8), # eth / MNE - (1, b'\xa9\x87\x7b\x1e\x05\xd0\x35\x89\x91\x31\xdb\xd1\xe4\x03\x82\x51\x66\xd0\x9f\x92', 'MNT', 18), # eth / Media Network Token - (1, b'\x83\xce\xe9\xe0\x86\xa7\x7e\x49\x2e\xe0\xbb\x93\xc2\xb0\x43\x7a\xd6\xfd\xec\xcc', 'MNTP', 18), # eth / Goldmint MNT Prelaunch Token - (1, b'\x95\x7c\x30\xab\x04\x26\xe0\xc9\x3c\xd8\x24\x1e\x2c\x60\x39\x2d\x08\xc6\xac\x8e', 'MOD', 0), # eth / Modum - (1, b'\x82\x12\x5a\xfe\x01\x81\x9d\xff\x15\x35\xd0\xd6\x27\x6d\x57\x04\x52\x91\xb6\xc0', 'MRL', 18), # eth / Marcelo - (1, b'\x21\xf0\xf0\xfd\x31\x41\xee\x9e\x11\xb3\xd7\xf1\x3a\x10\x28\xcd\x51\x5f\x45\x9c', 'MRP', 18), # eth / MoneyRebel Token - (1, b'\xab\x6c\xf8\x7a\x50\xf1\x7d\x7f\x5e\x1f\xea\xf8\x1b\x6f\xe9\xff\xbe\x8e\xbf\x84', 'MRV', 18), # eth / MRV - (1, b'\x68\xaa\x3f\x23\x2d\xa9\xbd\xc2\x34\x34\x65\x54\x57\x94\xef\x3e\xea\x52\x09\xbd', 'MSP', 18), # eth / Mothership - (1, b'\x90\x5e\x33\x7c\x6c\x86\x45\x26\x3d\x35\x21\x20\x5a\xa3\x7b\xf4\xd0\x34\xe7\x45', 'MTC', 18), # eth / Medical Token Currency - (1, b'\xaf\x4d\xce\x16\xda\x28\x77\xf8\xc9\xe0\x05\x44\xc9\x3b\x62\xac\x40\x63\x1f\x16', 'MTH', 5), # eth / Monetha - (1, b'\xf4\x33\x08\x93\x66\x89\x9d\x83\xa9\xf2\x6a\x77\x3d\x59\xec\x7e\xcf\x30\x35\x5e', 'MTL', 8), # eth / MetalPay - (1, b'\x41\xdb\xec\xc1\xcd\xc5\x51\x7c\x6f\x76\xf6\xa6\xe8\x36\xad\xbe\xe2\x75\x4d\xe3', 'MTN', 18), # eth / MedToken - (1, b'\x7f\xc4\x08\x01\x11\x65\x76\x0e\xe3\x1b\xe2\xbf\x20\xda\xf4\x50\x35\x66\x92\xaf', 'MTR', 8), # eth / Mitrav - (1, b'\x1e\x49\xff\x77\xc3\x55\xa3\xe3\x8d\x66\x51\xce\x84\x04\xaf\x0e\x48\xc5\x39\x5f', 'MTRc', 18), # eth / MTRCToken - (1, b'\x0a\xf4\x4e\x27\x84\x63\x72\x18\xdd\x1d\x32\xa3\x22\xd4\x4e\x60\x3a\x8f\x0c\x6a', 'MTX', 18), # eth / MTX - (1, b'\x51\x56\x69\xd3\x08\xf8\x87\xfd\x83\xa4\x71\xc7\x76\x4f\x5d\x08\x48\x86\xd3\x4d', 'MUXE', 18), # eth / MUXE - (1, b'\x8a\x77\xe4\x09\x36\xbb\xc2\x7e\x80\xe9\xa3\xf5\x26\x36\x8c\x96\x78\x69\xc8\x6d', 'MVP', 18), # eth / Merculet - (1, b'\x64\x25\xc6\xbe\x90\x2d\x69\x2a\xe2\xdb\x75\x2b\x3c\x26\x8a\xfa\xdb\x09\x9d\x3b', 'MWAT', 18), # eth / RED MWAT - (1, b'\xf7\xe9\x83\x78\x16\x09\x01\x23\x07\xf2\x51\x4f\x63\xd5\x26\xd8\x3d\x24\xf4\x66', 'MYD', 16), # eth / MYD - (1, b'\xa6\x45\x26\x4c\x56\x03\xe9\x6c\x3b\x0b\x07\x8c\xda\xb6\x87\x33\x79\x4b\x0a\x71', 'MYST', 8), # eth / Mysterium - (1, b'\x8d\x80\xde\x8a\x78\x19\x83\x96\x32\x9d\xfa\x76\x9a\xd5\x4d\x24\xbf\x90\xe7\xaa', 'NAC', 18), # eth / Nami ICO - (1, b'\xff\xe0\x2e\xe4\xc6\x9e\xdf\x1b\x34\x0f\xca\xd6\x4f\xbd\x6b\x37\xa7\xb9\xe2\x65', 'NANJ', 8), # eth / NANJCOIN - (1, b'\x58\x80\x47\x36\x5d\xf5\xba\x58\x9f\x92\x36\x04\xaa\xc2\x3d\x67\x35\x55\xc6\x23', 'NAVI', 18), # eth / NaviToken - (1, b'\x17\xf8\xaf\xb6\x3d\xfc\xdc\xc9\x0e\xbe\x6e\x84\xf0\x60\xcc\x30\x6a\x98\x25\x7d', 'NBAI', 18), # eth / NebulaAiToken - (1, b'\x80\x98\x26\xcc\xea\xb6\x8c\x38\x77\x26\xaf\x96\x27\x13\xb6\x4c\xb5\xcb\x3c\xca', 'nCash', 18), # eth / NucleusVision - (1, b'\x9e\x46\xa3\x8f\x5d\xaa\xbe\x86\x83\xe1\x07\x93\xb0\x67\x49\xee\xf7\xd7\x33\xd1', 'NCT', 18), # eth / Nectar - (1, b'\xa5\x4d\xdc\x7b\x3c\xce\x7f\xc8\xb1\xe3\xfa\x02\x56\xd0\xdb\x80\xd2\xc1\x09\x70', 'NDC', 18), # eth / Neverdie - (1, b'\xcc\x80\xc0\x51\x05\x7b\x77\x4c\xd7\x50\x67\xdc\x48\xf8\x98\x7c\x4e\xb9\x7a\x5e', 'NEC', 18), # eth / Ethfinex Nectar Token - (1, b'\xcf\xb9\x86\x37\xbc\xae\x43\xc1\x33\x23\xea\xa1\x73\x1c\xed\x2b\x71\x69\x62\xfd', 'NET', 18), # eth / NIMIQ - (1, b'\xa8\x23\xe6\x72\x20\x06\xaf\xe9\x9e\x91\xc3\x0f\xf5\x29\x50\x52\xfe\x6b\x8e\x32', 'NEU', 18), # eth / NEU Fund - (1, b'\x72\xdd\x4b\x6b\xd8\x52\xa3\xaa\x17\x2b\xe4\xd6\xc5\xa6\xdb\xec\x58\x8c\xf1\x31', 'NGC', 18), # eth / NAGA Coin - (1, b'\xe2\x65\x17\xa9\x96\x72\x99\x45\x3d\x3f\x1b\x48\xaa\x00\x5e\x61\x27\xe6\x72\x10', 'NIMFA', 18), # eth / Ninfa Money - (1, b'\x17\x76\xe1\xf2\x6f\x98\xb1\xa5\xdf\x9c\xd3\x47\x95\x3a\x26\xdd\x3c\xb4\x66\x71', 'NMR', 18), # eth / NMR - (1, b'\x64\x3b\x68\x70\xbe\xab\xee\x94\x1b\x92\x60\xa0\xa8\x78\xbc\xf4\xa6\x1f\xb0\xf1', 'NONE', 0), # eth / None - (1, b'\xec\x46\xf8\x20\x7d\x76\x60\x12\x45\x4c\x40\x8d\xe2\x10\xbc\xbc\x22\x43\xe7\x1c', 'NOX', 18), # eth / NOX - (1, b'\x4c\xe6\xb3\x62\xbc\x77\xa2\x49\x66\xdd\xa9\x07\x8f\x9c\xef\x81\xb3\xb8\x86\xa7', 'NPER', 18), # eth / NPER - (1, b'\xa1\x5c\x7e\xbe\x1f\x07\xca\xf6\xbf\xf0\x97\xd8\xa5\x89\xfb\x8a\xc4\x9a\xe5\xb3', 'NPXS', 18), # eth / Pundi X Token - (1, b'\xb9\x13\x18\xf3\x5b\xdb\x26\x2e\x94\x23\xbc\x7c\x7c\x2a\x3a\x93\xdd\x93\xc9\x2c', 'NULS', 18), # eth / NULS - (1, b'\x57\xab\x1e\x02\xfe\xe2\x37\x74\x58\x0c\x11\x97\x40\x12\x9e\xac\x70\x81\xe9\xd3', 'nUSD', 18), # eth / Havven-Backed USD Nomins (nUSD) - (1, b'\x45\xe4\x2d\x65\x9d\x9f\x94\x66\xcd\x5d\xf6\x22\x50\x60\x33\x14\x5a\x9b\x89\xbc', 'NxC', 3), # eth / Nexium - (1, b'\x76\x27\xde\x4b\x93\x26\x3a\x6a\x75\x70\xb8\xda\xfa\x64\xba\xe8\x12\xe5\xc3\x94', 'NXX', 8), # eth / NXX - (1, b'\x5c\x61\x83\xd1\x0a\x00\xcd\x74\x7a\x6d\xbb\x5f\x65\x8a\xd5\x14\x38\x3e\x94\x19', 'NXX OLD', 8), # eth / NXX OLD - (1, b'\x5e\x88\x8b\x83\xb7\x28\x7e\xed\x4f\xb7\xda\x7b\x7d\x0a\x0d\x4c\x73\x5d\x94\xb3', 'OAK', 18), # eth / OAK - (1, b'\x70\x1c\x24\x4b\x98\x8a\x51\x3c\x94\x59\x73\xde\xfa\x05\xde\x93\x3b\x23\xfe\x1d', 'OAX', 18), # eth / OAX - (1, b'\x02\x35\xfe\x62\x4e\x04\x4a\x05\xee\xd7\xa4\x3e\x16\xe3\x08\x3b\xc8\xa4\x28\x7a', 'OCC', 18), # eth / Original Crypto Coin - (1, b'\x6f\x53\x9a\x94\x56\xa5\xbc\xb6\x33\x4a\x1a\x41\x20\x7c\x37\x88\xf5\x82\x52\x07', 'OHNI', 18), # eth / Ohni - (1, b'\x7f\x21\x76\xce\xb1\x6d\xcb\x64\x8d\xc9\x24\xef\xf6\x17\xc3\xdc\x2b\xef\xd3\x0d', 'OHNI', 0), # eth / OHNI - (1, b'\xbe\xef\x54\x6a\xc8\xa4\xe0\xa8\x0d\xc1\xe2\xd6\x96\x96\x8e\xf5\x41\x38\xf1\xd4', 'OJX', 18), # eth / Ojooo Coin - (1, b'\xc6\x6e\xa8\x02\x71\x7b\xfb\x98\x33\x40\x02\x64\xdd\x12\xc2\xbc\xea\xa3\x4a\x6d', 'OLD_MKR', 18), # eth / MakerDAO - (1, b'\xd2\x61\x14\xcd\x6e\xe2\x89\xac\xcf\x82\x35\x0c\x8d\x84\x87\xfe\xdb\x8a\x0c\x07', 'OMG', 18), # eth / OMG - (1, b'\xb2\x3b\xe7\x35\x73\xbc\x7e\x03\xdb\x6e\x5d\xfc\x62\x40\x53\x68\x71\x6d\x28\xa8', 'ONEK', 18), # eth / One K Token - (1, b'\xd3\x41\xd1\x68\x0e\xee\xe3\x25\x5b\x8c\x4c\x75\xbc\xce\x7e\xb5\x7f\x14\x4d\xae', 'onG', 18), # eth / onG - (1, b'\x69\xc4\xbb\x24\x0c\xf0\x5d\x51\xee\xab\x69\x85\xba\xb3\x55\x27\xd0\x4a\x8c\x64', 'OPEN', 8), # eth / OPEN - (1, b'\xe9\xde\x1c\x63\x07\x53\xa1\x5d\x70\x21\xcc\x56\x34\x29\xc2\x1d\x48\x87\x50\x6f', 'OPEN', 8), # eth / OPEN - (1, b'\x43\x55\xfc\x16\x0f\x74\x32\x8f\x9b\x38\x3d\xf2\xec\x58\x9b\xb3\xdf\xd8\x2b\xa0', 'OPT', 18), # eth / Opus Foundation - (1, b'\xff\x56\xcc\x6b\x1e\x6d\xed\x34\x7a\xa0\xb7\x67\x6c\x85\xab\x0b\x3d\x08\xb0\xfa', 'ORBS', 18), # eth / Orbs - (1, b'\x2c\x4e\x8f\x2d\x74\x61\x13\xd0\x69\x6c\xe8\x9b\x35\xf0\xd8\xbf\x88\xe0\xae\xca', 'OST', 18), # eth / Simple Token 'OST' - (1, b'\x65\xa1\x50\x14\x96\x4f\x21\x02\xff\x58\x64\x7e\x16\xa1\x6a\x6b\x9e\x14\xbc\xf6', 'Ox Fina', 3), # eth / Ox Fina - (1, b'\xfe\xda\xe5\x64\x26\x68\xf8\x63\x6a\x11\x98\x7f\xf3\x86\xbf\xd2\x15\xf9\x42\xee', 'PAL', 18), # eth / PolicyPal Network - (1, b'\xea\x5f\x88\xe5\x4d\x98\x2c\xbb\x0c\x44\x1c\xde\x4e\x79\xbc\x30\x5e\x5b\x43\xbc', 'PARETO', 18), # eth / PARETO - (1, b'\xbb\x1f\xa4\xfd\xeb\x34\x59\x73\x3b\xf6\x7e\xbc\x6f\x89\x30\x03\xfa\x97\x6a\x82', 'PAT', 18), # eth / Pangea Arbitration Token - (1, b'\x69\x44\x04\x59\x5e\x30\x75\xa9\x42\x39\x7f\x46\x6a\xac\xd4\x62\xff\x1a\x7b\xd0', 'PATENTS', 18), # eth / PATENTS - (1, b'\xf8\x13\xf3\x90\x2b\xbc\x00\xa6\xdc\xe3\x78\x63\x4d\x3b\x79\xd8\x4f\x98\x03\xd7', 'PATH', 18), # eth / PATH - (1, b'\xb9\x70\x48\x62\x8d\xb6\xb6\x61\xd4\xc2\xaa\x83\x3e\x95\xdb\xe1\xa9\x05\xb2\x80', 'PAY', 18), # eth / TenX - (1, b'\x55\x64\x8d\xe1\x98\x36\x33\x85\x49\x13\x0b\x1a\xf5\x87\xf1\x6b\xea\x46\xf6\x6b', 'PBL', 18), # eth / PBL - (1, b'\xf4\xc0\x7b\x18\x65\xbc\x32\x6a\x3c\x01\x33\x94\x92\xca\x75\x38\xfd\x03\x8c\xc0', 'PBT', 4), # eth / Primalbase Token (PBT) - (1, b'\xfc\xac\x7a\x75\x15\xe9\xa9\xd7\x61\x9f\xa7\x7a\x1f\xa7\x38\x11\x1f\x66\x72\x7e', 'PCH', 18), # eth / PITCH - (1, b'\x36\x18\x51\x6f\x45\xcd\x3c\x91\x3f\x81\xf9\x98\x7a\xf4\x10\x77\x93\x2b\xc4\x0d', 'PCL', 8), # eth / Peculium - (1, b'\x53\x14\x8b\xb4\x55\x17\x07\xed\xf5\x1a\x1e\x8d\x7a\x93\x69\x8d\x18\x93\x12\x25', 'PCLOLD', 8), # eth / PeculiumOLD - (1, b'\x58\x84\x96\x9e\xc0\x48\x05\x56\xe1\x1d\x11\x99\x80\x13\x6a\x4c\x17\xed\xde\xd1', 'PET', 18), # eth / PETHEREUM - (1, b'\xec\x18\xf8\x98\xb4\x07\x6a\x3e\x18\xf1\x08\x9d\x33\x37\x6c\xc3\x80\xbd\xe6\x1d', 'PETRO', 18), # eth / PETRO - (1, b'\x55\xc2\xa0\xc1\x71\xd9\x20\x84\x35\x60\x59\x4d\xe3\xd6\xee\xcc\x09\xef\xc0\x98', 'PEXT', 4), # eth / PEX-Token - (1, b'\xe6\x45\x09\xf0\xbf\x07\xce\x2d\x29\xa7\xef\x19\xa8\xa9\xbc\x06\x54\x77\xc1\xb4', 'PIPL', 8), # eth / PIPL Coin - (1, b'\x8e\xff\xd4\x94\xeb\x69\x8c\xc3\x99\xaf\x62\x31\xfc\xcd\x39\xe0\x8f\xd2\x0b\x15', 'PIX', 0), # eth / PIX - (1, b'\x59\x41\x6a\x25\x62\x8a\x76\xb4\x73\x0e\xc5\x14\x86\x11\x4c\x32\xe0\xb5\x82\xa1', 'PLASMA', 6), # eth / PLASMA - (1, b'\xe4\x77\x29\x2f\x1b\x32\x68\x68\x7a\x29\x37\x61\x16\xb0\xed\x27\xa9\xc7\x61\x70', 'PLAY', 18), # eth / HeroCoin - (1, b'\x0a\xff\xa0\x6e\x7f\xbe\x5b\xc9\xa7\x64\xc9\x79\xaa\x66\xe8\x25\x6a\x63\x1f\x02', 'PLBT', 6), # eth / Polybius - (1, b'\xe3\x81\x85\x04\xc1\xb3\x2b\xf1\x55\x7b\x16\xc2\x38\xb2\xe0\x1f\xd3\x14\x9c\x17', 'PLR', 18), # eth / Pillar Project - (1, b'\xd8\x91\x2c\x10\x68\x1d\x8b\x21\xfd\x37\x42\x24\x4f\x44\x65\x8d\xba\x12\x26\x4e', 'PLU', 18), # eth / Plutus - (1, b'\x0e\x09\x89\xb1\xf9\xb8\xa3\x89\x83\xc2\xba\x80\x53\x26\x9c\xa6\x2e\xc9\xb1\x95', 'POE', 8), # eth / Po.et Tokens - (1, b'\x43\xf6\xa1\xbe\x99\x2d\xee\x40\x87\x21\x74\x84\x90\x77\x2b\x15\x14\x3c\xe0\xa7', 'POIN', 0), # eth / Potatoin - (1, b'\x99\x92\xec\x3c\xf6\xa5\x5b\x00\x97\x8c\xdd\xf2\xb2\x7b\xc6\x88\x2d\x88\xd1\xec', 'POLY', 18), # eth / Polymath Network - (1, b'\x77\x9b\x7b\x71\x3c\x86\xe3\xe6\x77\x4f\x50\x40\xd9\xcc\xc2\xd4\x3a\xd3\x75\xf8', 'POOL', 8), # eth / Stake Pool - (1, b'\xee\x60\x9f\xe2\x92\x12\x8c\xad\x03\xb7\x86\xdb\xb9\xbc\x26\x34\xcc\xdb\xe7\xfc', 'POS', 18), # eth / PoSToken - (1, b'\x59\x58\x32\xf8\xfc\x6b\xf5\x9c\x85\xc5\x27\xfe\xc3\x74\x0a\x1b\x7a\x36\x12\x69', 'POWR', 6), # eth / PowerLedger - (1, b'\xc4\x22\x09\xac\xcc\x14\x02\x9c\x10\x12\xfb\x56\x80\xd9\x5f\xbd\x60\x36\xe2\xa0', 'PPP', 18), # eth / PayPie - (1, b'\xd4\xfa\x14\x60\xf5\x37\xbb\x90\x85\xd2\x2c\x7b\xcc\xb5\xdd\x45\x0e\xf2\x8e\x3a', 'PPT', 8), # eth / Populous - (1, b'\x88\xa3\xe4\xf3\x5d\x64\xaa\xd4\x1a\x6d\x40\x30\xac\x9a\xfe\x43\x56\xcb\x84\xfa', 'PRE', 18), # eth / Presearch - (1, b'\x77\x28\xdf\xef\x5a\xbd\x46\x86\x69\xeb\x7f\x9b\x48\xa7\xf7\x0a\x50\x1e\xd2\x9d', 'PRG', 6), # eth / PRG - (1, b'\x18\x44\xb2\x15\x93\x26\x26\x68\xb7\x24\x8d\x0f\x57\xa2\x20\xca\xab\xa4\x6a\xb9', 'PRL', 18), # eth / Oyster Pearl - (1, b'\x22\x6b\xb5\x99\xa1\x2c\x82\x64\x76\xe3\xa7\x71\x45\x46\x97\xea\x52\xe9\xe2\x20', 'PRO', 8), # eth / Propy - (1, b'\xa3\x14\x9e\x0f\xa0\x06\x1a\x90\x07\xfa\xf3\x07\x07\x4c\xdc\xd2\x90\xf0\xe2\xfd', 'PRON', 8), # eth / PronCoin - (1, b'\x76\x41\xb2\xca\x9d\xdd\x58\xad\xdf\x6e\x33\x81\xc1\xf9\x94\xaa\xc5\xf1\xa3\x2f', 'PRPS', 18), # eth / Purpose - (1, b'\xd9\x4f\x27\x78\xe2\xb3\x91\x3c\x53\x63\x7a\xe6\x06\x47\x59\x8b\xe5\x88\xc5\x70', 'PRPS', 18), # eth / Purpose - (1, b'\x16\x37\x33\xbc\xc2\x8d\xbf\x26\xb4\x1a\x8c\xfa\x83\xe3\x69\xb5\xb3\xaf\x74\x1b', 'PRS', 18), # eth / Persians - (1, b'\x0c\x04\xd4\xf3\x31\xda\x8d\xf7\x5f\x9e\x2e\x27\x1e\x3f\x3f\x14\x94\xc6\x6c\x36', 'PRSP', 9), # eth / PRSP - (1, b'\x66\x49\x7a\x28\x3e\x0a\x00\x7b\xa3\x97\x4e\x83\x77\x84\xc6\xae\x32\x34\x47\xde', 'PT', 18), # eth / PornToken - (1, b'\x2a\x8e\x98\xe2\x56\xf3\x22\x59\xb5\xe5\xcb\x55\xdd\x63\xc8\xe8\x91\x95\x06\x66', 'PTC', 18), # eth / ParrotCoin - (1, b'\x8a\xe4\xbf\x2c\x33\xa8\xe6\x67\xde\x34\xb5\x49\x38\xb0\xcc\xd0\x3e\xb8\xcc\x06', 'PTOY', 8), # eth / PTOY - (1, b'\x55\x12\xe1\xd6\xa7\xbe\x42\x4b\x43\x23\x12\x6b\x4f\x9e\x86\xd0\x23\xf9\x57\x64', 'PTWO', 18), # eth / PornTokenV2 - (1, b'\xef\x6b\x4c\xe8\xc9\xbc\x83\x74\x4f\xbc\xde\x26\x57\xb3\x2e\xc1\x87\x90\x45\x8a', 'PUC', 0), # eth / Pour Coin - (1, b'\xc1\x48\x30\xe5\x3a\xa3\x44\xe8\xc1\x46\x03\xa9\x12\x29\xa0\xb9\x25\xb0\xb2\x62', 'PXT', 8), # eth / Populous XBRL Token (PXT) - (1, b'\x61\x8e\x75\xac\x90\xb1\x2c\x60\x49\xba\x3b\x27\xf5\xd5\xf8\x65\x1b\x00\x37\xf6', 'QASH', 6), # eth / QASH - (1, b'\x67\x1a\xbb\xe5\xce\x65\x24\x91\x98\x53\x42\xe8\x54\x28\xeb\x1b\x07\xbc\x6c\x64', 'QAU', 8), # eth / QAU - (1, b'\x24\x67\xaa\x6b\x5a\x23\x51\x41\x6f\xd4\xc3\xde\xf8\x46\x2d\x84\x1f\xee\xec\xec', 'QBX', 18), # eth / qiibeeToken - (1, b'\xff\xaa\x5f\xfc\x45\x5d\x91\x31\xf8\xa2\x71\x3a\x74\x1f\xd1\x96\x03\x30\x50\x8b', 'QRG', 18), # eth / QRG - (1, b'\x69\x7b\xea\xc2\x8b\x09\xe1\x22\xc4\x33\x2d\x16\x39\x85\xe8\xa7\x31\x21\xb9\x7f', 'QRL', 8), # eth / QRL - (1, b'\x99\xea\x4d\xb9\xee\x77\xac\xd4\x0b\x11\x9b\xd1\xdc\x4e\x33\xe1\xc0\x70\xb8\x0d', 'QSP', 18), # eth / Quantstamp Token - (1, b'\x2c\x3c\x1f\x05\x18\x7d\xba\x7a\x5f\x2d\xd4\x7d\xca\x57\x28\x1c\x4d\x4f\x18\x3f', 'QTQ', 18), # eth / TiiQu's Q Token - (1, b'\x9a\x64\x2d\x6b\x33\x68\xdd\xc6\x62\xca\x24\x4b\xad\xf3\x2c\xda\x71\x60\x05\xbc', 'QTUM', 18), # eth / Qtum - (1, b'\x45\xed\xb5\x35\x94\x2a\x8c\x84\xd9\xf4\xb5\xd3\x7e\x1b\x25\xf9\x1e\xa4\x80\x4c', 'RAO', 18), # eth / RadioYo - (1, b'\xfc\x2c\x4d\x8f\x95\x00\x2c\x14\xed\x0a\x7a\xa6\x51\x02\xca\xc9\xe5\x95\x3b\x5e', 'RBLX', 18), # eth / Rublix - (1, b'\xf9\x70\xb8\xe3\x6e\x23\xf7\xfc\x3f\xd7\x52\xee\xa8\x6f\x8b\xe8\xd8\x33\x75\xa6', 'RCN', 18), # eth / Ripio Credit Network - (1, b'\x2a\x3a\xa9\xec\xa4\x1e\x72\x0e\xd4\x6b\x5a\x70\xd6\xc3\x7e\xfa\x47\xf7\x68\xac', 'RCT', 18), # eth / RCT - (1, b'\x25\x5a\xa6\xdf\x07\x54\x0c\xb5\xd3\xd2\x97\xf0\xd0\xd4\xd8\x4c\xb5\x2b\xc8\xe6', 'RDN', 18), # eth / Raiden Network - (1, b'\x76\x7b\xa2\x91\x5e\xc3\x44\x01\x5a\x79\x38\xe3\xee\xdf\xec\x27\x85\x19\x5d\x05', 'REA', 18), # eth / Realisto - (1, b'\x5f\x53\xf7\xa8\x07\x56\x14\xb6\x99\xba\xad\x0b\xc2\xc8\x99\xf4\xba\xd8\xfb\xbf', 'REBL', 18), # eth / Rebellious - (1, b'\x76\x96\x0d\xcc\xd5\xa1\xfe\x79\x9f\x7c\x29\xbe\x9f\x19\xce\xb4\x62\x7a\xeb\x2f', 'RED', 18), # eth / Red Community Token - (1, b'\x40\x8e\x41\x87\x6c\xcc\xdc\x0f\x92\x21\x06\x00\xef\x50\x37\x26\x56\x05\x2a\x38', 'REN', 18), # eth / Republic Token - (1, b'\xe9\x43\x27\xd0\x7f\xc1\x79\x07\xb4\xdb\x78\x8e\x5a\xdf\x2e\xd4\x24\xad\xdf\xf6', 'REP', 18), # eth / Augur - (1, b'\x8f\x82\x21\xaf\xbb\x33\x99\x8d\x85\x84\xa2\xb0\x57\x49\xba\x73\xc3\x7a\x93\x8a', 'REQ', 18), # eth / Request Network - (1, b'\xf0\x5a\x93\x82\xa4\xc3\xf2\x9e\x27\x84\x50\x27\x54\x29\x3d\x88\xb8\x35\x10\x9c', 'REX', 18), # eth / REX - (1, b'\xd0\x92\x9d\x41\x19\x54\xc4\x74\x38\xdc\x1d\x87\x1d\xd6\x08\x1f\x5c\x5e\x14\x9c', 'RFR', 4), # eth / Refereum - (1, b'\xdd\x00\x72\x78\xb6\x67\xf6\xbe\xf5\x2f\xd0\xa4\xc2\x36\x04\xaa\x1f\x96\x03\x9a', 'RIPT', 8), # eth / RiptideCoin - (1, b'\x60\x7f\x4c\x5b\xb6\x72\x23\x0e\x86\x72\x08\x55\x32\xf7\xe9\x01\x54\x4a\x73\x75', 'RLC', 9), # eth / IEx.ec - (1, b'\xcc\xed\x5b\x82\x88\x08\x6b\xe8\xc3\x8e\x23\x56\x7e\x68\x4c\x37\x40\xbe\x4d\x48', 'RLT', 10), # eth / RLT - (1, b'\xbe\x99\xb0\x97\x09\xfc\x75\x3b\x09\xbc\xf5\x57\xa9\x92\xf6\x60\x5d\x59\x97\xb0', 'RLTY', 8), # eth / SMARTRealty - (1, b'\x4a\x42\xd2\xc5\x80\xf8\x3d\xce\x40\x4a\xca\xd1\x8d\xab\x26\xdb\x11\xa1\x75\x0e', 'RLX', 18), # eth / Relex - (1, b'\x09\x96\xbf\xb5\xd0\x57\xfa\xa2\x37\x64\x0e\x25\x06\xbe\x7b\x4f\x9c\x46\xde\x0b', 'RNDR', 18), # eth / Render Token - (1, b'\xa4\x01\x06\x13\x4c\x5b\xf4\xc4\x14\x11\x55\x4e\x6d\xb9\x9b\x95\xa1\x5e\xd9\xd8', 'ROCK', 18), # eth / Rocket Token - (1, b'\xc9\xde\x4b\x7f\x0c\x3d\x99\x1e\x96\x71\x58\xe4\xd4\xbf\xa4\xb5\x1e\xc0\xb1\x14', 'ROK', 18), # eth / Rocketchain - (1, b'\x49\x93\xcb\x95\xc7\x44\x3b\xdc\x06\x15\x5c\x5f\x56\x88\xbe\x9d\x8f\x69\x99\xa5', 'ROUND', 18), # eth / ROUND - (1, b'\xb4\xef\xd8\x5c\x19\x99\x9d\x84\x25\x13\x04\xbd\xa9\x9e\x90\xb9\x23\x00\xbd\x93', 'RPL', 18), # eth / Rocket Pool - (1, b'\x54\xb2\x93\x22\x60\x00\xcc\xbf\xc0\x4d\xf9\x02\xee\xc5\x67\xcb\x4c\x35\xa9\x03', 'RTN', 18), # eth / RiderToken - (1, b'\x41\xf6\x15\xe2\x4f\xab\xd2\xb0\x97\xa3\x20\xe9\xe6\xc1\xf4\x48\xcb\x40\x52\x1c', 'RVL', 18), # eth / RVL - (1, b'\x3d\x1b\xa9\xbe\x9f\x66\xb8\xee\x10\x19\x11\xbc\x36\xd3\xfb\x56\x2e\xac\x22\x44', 'RVT', 18), # eth / Rivetz - (1, b'\x1e\xc8\xfe\x51\xa9\xb6\xa3\xa6\xc4\x27\xd1\x7d\x9e\xcc\x30\x60\xfb\xc4\xa4\x5c', 'S-A-PAT', 18), # eth / S-A-PAT - (1, b'\x3e\xb9\x1d\x23\x7e\x49\x1e\x0d\xee\x85\x82\xc4\x02\xd8\x5c\xb4\x40\xfb\x6b\x54', 'S-ETH', 18), # eth / S-ETH - (1, b'\x41\x56\xd3\x34\x2d\x5c\x38\x5a\x87\xd2\x64\xf9\x06\x53\x73\x35\x92\x00\x05\x81', 'SALT', 8), # eth / Salt Lending Token - (1, b'\x7c\x5a\x0c\xe9\x26\x7e\xd1\x9b\x22\xf8\xca\xe6\x53\xf1\x98\xe3\xe8\xda\xf0\x98', 'SAN', 18), # eth / Santiment - (1, b'\x78\xfe\x18\xe4\x1f\x43\x6e\x19\x81\xa3\xa6\x0d\x15\x57\xc8\xa7\xa9\x37\x04\x61', 'SCANDI', 2), # eth / Scandiweb Coin - (1, b'\xd7\x63\x17\x87\xb4\xdc\xc8\x7b\x12\x54\xcf\xd1\xe5\xce\x48\xe9\x68\x23\xde\xe8', 'SCL', 8), # eth / SocialCoin - (1, b'\x4c\xa7\x41\x85\x53\x2d\xc1\x78\x95\x27\x19\x4e\x5b\x9c\x86\x6d\xd3\x3f\x4e\x82', 'SenSatorI', 18), # eth / SenSatorI Token - (1, b'\x67\x45\xfa\xb6\x80\x1e\x37\x6c\xd2\x4f\x03\x57\x2b\x9c\x9b\x0d\x4e\xdd\xdc\xcf', 'SENSE', 8), # eth / Sensay - (1, b'\xe0\x6e\xda\x74\x35\xba\x74\x9b\x04\x73\x80\xce\xd4\x91\x21\xdd\xe9\x33\x34\xae', 'SET', 0), # eth / SET - (1, b'\x98\xf5\xe9\xb7\xf0\xe3\x39\x56\xc0\x44\x3e\x81\xbf\x7d\xeb\x8b\x5b\x1e\xd5\x45', 'SEXY', 18), # eth / Sexy Token - (1, b'\xa1\xcc\xc1\x66\xfa\xf0\xe9\x98\xb3\xe3\x32\x25\xa1\xa0\x30\x1b\x1c\x86\x11\x9d', 'SGEL', 18), # eth / SGELDER - (1, b'\x37\x42\x75\x76\x32\x4f\xe1\xf3\x62\x5c\x91\x02\x67\x47\x72\xd7\xcf\x71\x37\x7d', 'SGT', 18), # eth / SelfieYo Gold Token - (1, b'\xd2\x48\xb0\xd4\x8e\x44\xaa\xf9\xc4\x9a\xea\x03\x12\xbe\x7e\x13\xa6\xdc\x14\x68', 'SGT', 1), # eth / SGT - (1, b'\xef\x2e\x99\x66\xeb\x61\xbb\x49\x4e\x53\x75\xd5\xdf\x8d\x67\xb7\xdb\x8a\x78\x0d', 'SHIT', 0), # eth / SHIT - (1, b'\x8a\x18\x7d\x52\x85\xd3\x16\xbc\xbc\x9a\xda\xfc\x08\xb5\x1d\x70\xa0\xd8\xe0\x00', 'SIFT', 0), # eth / SIFT - (1, b'\x68\x88\xa1\x6e\xa9\x79\x2c\x15\xa4\xdc\xf2\xf6\xc6\x23\xd0\x55\xc8\xed\xe7\x92', 'SIG', 18), # eth / Signal - (1, b'\x2b\xdc\x0d\x42\x99\x60\x17\xfc\xe2\x14\xb2\x16\x07\xa5\x15\xda\x41\xa9\xe0\xc5', 'SKIN', 6), # eth / SKIN - (1, b'\x49\x94\xe8\x18\x97\xa9\x20\xc0\xfe\xa2\x35\xeb\x8c\xed\xee\xd3\xc6\xff\xf6\x97', 'SKO1', 18), # eth / Sikoba - (1, b'\x4c\x38\x2f\x8e\x09\x61\x5a\xc8\x6e\x08\xce\x58\x26\x6c\xc2\x27\xe7\xd4\xd9\x13', 'SKR', 6), # eth / SKR Token - (1, b'\x32\x4a\x48\xeb\xcb\xb4\x6e\x61\x99\x39\x31\xef\x9d\x35\xf6\x69\x7c\xd2\x90\x1b', 'SKRP', 18), # eth / Skraps - (1, b'\x6e\x34\xd8\xd8\x47\x64\xd4\x0f\x6d\x7b\x39\xcd\x56\x9f\xd0\x17\xbf\x53\x17\x7d', 'SKRP', 18), # eth / Skraps - (1, b'\xfd\xfe\x8b\x7a\xb6\xcf\x1b\xd1\xe3\xd1\x45\x38\xef\x40\x68\x62\x96\xc4\x20\x52', 'SKRP', 18), # eth / Skraps - (1, b'\x7a\x5f\xf2\x95\xdc\x82\x39\xd5\xc2\x37\x4e\x4d\x89\x42\x02\xaa\xf0\x29\xca\xb6', 'SLT', 3), # eth / Smartlands - (1, b'\x6f\x6d\xeb\x5d\xb0\xc4\x99\x4a\x82\x83\xa0\x1d\x6c\xfe\xeb\x27\xfc\x3b\xbe\x9c', 'SMART', 0), # eth / Smart Billions - (1, b'\x2d\xcf\xaa\xc1\x1c\x9e\xeb\xd8\xc6\xc4\x21\x03\xfe\x9e\x2a\x6a\xd2\x37\xaf\x27', 'SMT', 18), # eth / Smart Node - (1, b'\x55\xf9\x39\x85\x43\x1f\xc9\x30\x40\x77\x68\x7a\x35\xa1\xba\x10\x3d\xc1\xe0\x81', 'SMT', 18), # eth / SmartMesh - (1, b'\x78\xeb\x8d\xc6\x41\x07\x7f\x04\x9f\x91\x06\x59\xb6\xd5\x80\xe8\x0d\xc4\xd2\x37', 'SMT', 8), # eth / Social Media Market - (1, b'\xf4\x13\x41\x46\xaf\x2d\x51\x1d\xd5\xea\x8c\xdb\x1c\x4a\xc8\x8c\x57\xd6\x04\x04', 'SNC', 18), # eth / SNC - (1, b'\xf3\x33\xb2\xac\xe9\x92\xac\x2b\xbd\x87\x98\xbf\x57\xbc\x65\xa0\x61\x84\xaf\xba', 'SND', 0), # eth / Sandcoin - (1, b'\xcf\xd6\xae\x8b\xf1\x3f\x42\xde\x14\x86\x73\x51\xea\xff\x7a\x8a\x3b\x9f\xbb\xe7', 'SNG', 8), # eth / SINERGIA - (1, b'\xae\xc2\xe8\x7e\x0a\x23\x52\x66\xd9\xc5\xad\xc9\xde\xb4\xb2\xe2\x9b\x54\xd0\x09', 'SNGLS', 0), # eth / SingularDTV - (1, b'\x44\xf5\x88\xae\xeb\x8c\x44\x47\x14\x39\xd1\x27\x0b\x36\x03\xc6\x6a\x92\x62\xf1', 'SNIP', 18), # eth / SNIP - (1, b'\x98\x3f\x6d\x60\xdb\x79\xea\x8c\xa4\xeb\x99\x68\xc6\xaf\xf8\xcf\xa0\x4b\x3c\x63', 'SNM', 18), # eth / SNM - (1, b'\xbd\xc5\xba\xc3\x9d\xbe\x13\x2b\x1e\x03\x0e\x89\x8a\xe3\x83\x00\x17\xd7\xd9\x69', 'SNOV', 18), # eth / SNOV - (1, b'\x74\x4d\x70\xfd\xbe\x2b\xa4\xcf\x95\x13\x16\x26\x61\x4a\x17\x63\xdf\x80\x5b\x9e', 'SNT', 18), # eth / Status Network Token - (1, b'\x1f\x54\x63\x8b\x77\x37\x19\x3f\xfd\x86\xc1\x9e\xc5\x19\x07\xa7\xc4\x17\x55\xd8', 'SOL', 6), # eth / Sola Token - (1, b'\x42\xd6\x62\x2d\xec\xe3\x94\xb5\x49\x99\xfb\xd7\x3d\x10\x81\x23\x80\x6f\x6a\x18', 'SPANK', 18), # eth / SpankChain - (1, b'\x58\xbf\x7d\xf5\x7d\x9d\xa7\x11\x3c\x4c\xcb\x49\xd8\x46\x3d\x49\x08\xc7\x35\xcb', 'SPARC', 18), # eth / SPARC - (1, b'\x24\xae\xf3\xbf\x1a\x47\x56\x15\x00\xf9\x43\x0d\x74\xed\x40\x97\xc4\x7f\x51\xf2', 'SPARTA', 4), # eth / SPARTA - (1, b'\x85\x08\x93\x89\xc1\x4b\xd9\xc7\x7f\xc2\xb8\xf0\xc3\xd1\xdc\x33\x63\xbf\x06\xef', 'SPF', 18), # eth / Sportify - (1, b'\x20\xf7\xa3\xdd\xf2\x44\xdc\x92\x99\x97\x5b\x4d\xa1\xc3\x9f\x8d\x5d\x75\xf0\x5a', 'SPN', 6), # eth / Sapien - (1, b'\x68\xd5\x7c\x9a\x1c\x35\xf6\x3e\x2c\x83\xee\x8e\x49\xa6\x4e\x9d\x70\x52\x8d\x25', 'SRN', 18), # eth / Sirin Labs - (1, b'\xb1\x5f\xe5\xa1\x23\xe6\x47\xba\x59\x4c\xea\x7a\x1e\x64\x86\x46\xf9\x5e\xb4\xaa', 'SS', 18), # eth / Sharder - (1, b'\xbb\xff\x86\x2d\x90\x6e\x34\x8e\x99\x46\xbf\xb2\x13\x2e\xcb\x15\x7d\xa3\xd4\xb4', 'SS', 18), # eth / Sharder - (1, b'\x6e\x20\x50\xcb\xfb\x3e\xd8\xa4\xd3\x9b\x64\xcc\x9f\x47\xe7\x11\xa0\x3a\x5a\x89', 'SSH', 18), # eth / StreamShares - (1, b'\x9a\x00\x5c\x9a\x89\xbd\x72\xa4\xbd\x27\x72\x1e\x7a\x09\xa3\xc1\x1d\x2b\x03\xc4', 'STAC', 18), # eth / Starter Coin - (1, b'\xf7\x0a\x64\x2b\xd3\x87\xf9\x43\x80\xff\xb9\x04\x51\xc2\xc8\x1d\x4e\xb8\x2c\xbc', 'STAR', 18), # eth / Star Token - (1, b'\x62\x9a\xee\x55\xed\x49\x58\x1c\x33\xab\x27\xf9\x40\x3f\x79\x92\xa2\x89\xff\xd5', 'STC', 18), # eth / StrikeCoin Token - (1, b'\xae\x73\xb3\x8d\x1c\x9a\x8b\x27\x41\x27\xec\x30\x16\x0a\x49\x27\xc4\xd7\x18\x24', 'STK', 18), # eth / STK Token - (1, b'\x59\x93\x46\x77\x9e\x90\xfc\x3f\x5f\x99\x7b\x5e\xa7\x15\x34\x98\x20\xf9\x15\x71', 'STN', 4), # eth / Saturn Network - (1, b'\xb6\x4e\xf5\x1c\x88\x89\x72\xc9\x08\xcf\xac\xf5\x9b\x47\xc1\xaf\xbc\x0a\xb8\xac', 'STORJ', 8), # eth / STORJ - (1, b'\xd0\xa4\xb8\x94\x6c\xb5\x2f\x06\x61\x27\x3b\xfb\xc6\xfd\x0e\x0c\x75\xfc\x64\x33', 'STORM', 18), # eth / Storm Token - (1, b'\xec\xd5\x70\xbb\xf7\x47\x61\xb9\x60\xfa\x04\xcc\x10\xfe\x2c\x4e\x86\xff\xda\x36', 'STP', 8), # eth / StashPay - (1, b'\x5c\x3a\x22\x85\x10\xd2\x46\xb7\x8a\x37\x65\xc2\x02\x21\xcb\xf3\x08\x2b\x44\xa4', 'STQ', 18), # eth / Storiqa - (1, b'\x46\x49\x24\x73\x75\x5e\x8d\xf9\x60\xf8\x03\x48\x77\xf6\x17\x32\xd7\x18\xce\x96', 'STRC', 8), # eth / STRC - (1, b'\x00\x6b\xea\x43\xba\xa3\xf7\xa6\xf7\x65\xf1\x4f\x10\xa1\xa1\xb0\x83\x34\xef\x45', 'STX', 18), # eth / StoxToken - (1, b'\x12\x48\x0e\x24\xeb\x5b\xec\x1a\x9d\x43\x69\xca\xb6\xa8\x0c\xad\x3c\x0a\x37\x7a', 'SUB', 2), # eth / Substratum - (1, b'\x9e\x88\x61\x34\x18\xcf\x03\xdc\xa5\x4d\x6a\x2c\xf6\xad\x93\x4a\x78\xc7\xa1\x7a', 'SWM', 18), # eth / Swarm Fund Token - (1, b'\xb9\xe7\xf8\x56\x8e\x08\xd5\x65\x9f\x5d\x29\xc4\x99\x71\x73\xd8\x4c\xdf\x26\x07', 'SWT', 18), # eth / Swarm City Token - (1, b'\x12\xb3\x06\xfa\x98\xf4\xcb\xb8\xd4\x45\x7f\xdf\xf3\xa0\xa0\xa5\x6f\x07\xcc\xdf', 'SXDT', 18), # eth / Spectre.ai D-Token - (1, b'\x2c\x82\xc7\x3d\x5b\x34\xaa\x01\x59\x89\x46\x2b\x29\x48\xcd\x61\x6a\x37\x64\x1f', 'SXUT', 18), # eth / Spectre.ai U-Token - (1, b'\x10\xb1\x23\xfd\xdd\xe0\x03\x24\x31\x99\xaa\xd0\x35\x22\x06\x5d\xc0\x58\x27\xa0', 'SYN', 18), # eth / Synapse - (1, b'\xe7\x77\x5a\x6e\x9b\xcf\x90\x4e\xb3\x9d\xa2\xb6\x8c\x5e\xfb\x4f\x93\x60\xe0\x8c', 'TaaS', 6), # eth / Token-as-a-Service - (1, b'\xc2\x7a\x2f\x05\xfa\x57\x7a\x83\xba\x0f\xdb\x4c\x38\x44\x3c\x07\x18\x35\x65\x01', 'TAU', 18), # eth / Lamden Tau - (1, b'\xfa\xcc\xd5\xfc\x83\xc3\xe4\xc3\xc1\xac\x1e\xf3\x5d\x15\xad\xf0\x6b\xcf\x20\x9c', 'TBC2', 8), # eth / TBC2 - (1, b'\xaf\xe6\x05\x11\x34\x1a\x37\x48\x8d\xe2\x5b\xef\x35\x19\x52\x56\x2e\x31\xfc\xc1', 'TBT', 8), # eth / TBitBot - (1, b'\x2a\x1d\xba\xbe\x65\xc5\x95\xb0\x02\x2e\x75\x20\x8c\x34\x01\x41\x39\xd5\xd3\x57', 'TDH', 18), # eth / TrustedHealth - (1, b'\x85\xe0\x76\x36\x1c\xc8\x13\xa9\x08\xff\x67\x2f\x9b\xad\x15\x41\x47\x44\x02\xb2', 'TEL', 2), # eth / Telcoin - (1, b'\xa7\xf9\x76\xc3\x60\xeb\xbe\xd4\x46\x5c\x28\x55\x68\x4d\x1a\xae\x52\x71\xef\xa9', 'TFL', 8), # eth / TrueFlip - (1, b'\x38\x83\xf5\xe1\x81\xfc\xca\xf8\x41\x0f\xa6\x1e\x12\xb5\x9b\xad\x96\x3f\xb6\x45', 'THETA', 18), # eth / Theta Token - (1, b'\xfe\x7b\x91\x5a\x0b\xaa\x0e\x79\xf8\x5c\x55\x53\x26\x65\x13\xf7\xc1\xc0\x3e\xd0', 'THUG', 18), # eth / THUG - (1, b'\x65\x31\xf1\x33\xe6\xde\xeb\xe7\xf2\xdc\xe5\xa0\x44\x1a\xa7\xef\x33\x0b\x4e\x53', 'TIME', 8), # eth / Chronobank - (1, b'\x80\xbc\x55\x12\x56\x1c\x7f\x85\xa3\xa9\x50\x8c\x7d\xf7\x90\x1b\x37\x0f\xa1\xdf', 'TIO', 18), # eth / TIO - (1, b'\xea\x1f\x34\x6f\xaf\x02\x3f\x97\x4e\xb5\xad\xaf\x08\x8b\xbc\xdf\x02\xd7\x61\xf4', 'TIX', 18), # eth / Blocktix - (1, b'\xaa\xaf\x91\xd9\xb9\x0d\xf8\x00\xdf\x4f\x55\xc2\x05\xfd\x69\x89\xc9\x77\xe7\x3a', 'TKN', 8), # eth / TokenCard - (1, b'\x08\xf5\xa9\x23\x5b\x08\x17\x3b\x75\x69\xf8\x36\x45\xd2\xc7\xfb\x55\xe8\xcc\xd8', 'TNT', 8), # eth / Tierion Network Token - (1, b'\xcb\x3f\x90\x2b\xf9\x76\x26\x39\x1b\xf8\xba\x87\x26\x4b\xbc\x3d\xc1\x34\x69\xbe', 'TRC', 18), # eth / The Real Coin - (1, b'\x56\x6f\xd7\x99\x9b\x1f\xc3\x98\x80\x22\xbd\x38\x50\x7a\x48\xf0\xbc\xf2\x2c\x77', 'TRCN', 18), # eth / The Real Coin - (1, b'\xcb\x94\xbe\x6f\x13\xa1\x18\x2e\x4a\x4b\x61\x40\xcb\x7b\xf2\x02\x5d\x28\xe4\x1b', 'TRST', 6), # eth / TRST - (1, b'\xf2\x30\xb7\x90\xe0\x53\x90\xfc\x82\x95\xf4\xd3\xf6\x03\x32\xc9\x3b\xed\x42\xe2', 'TRX', 6), # eth / Tron Lab Token - (1, b'\x2e\xf1\xab\x8a\x26\x18\x7c\x58\xbb\x8a\xae\xb1\x1b\x2f\xc6\xd2\x5c\x5c\x07\x16', 'TWN', 18), # eth / The World News - (1, b'\xfb\xd0\xd1\xc7\x7b\x50\x17\x96\xa3\x5d\x86\xcf\x91\xd6\x5d\x97\x78\xee\xe6\x95', 'TWNKL', 3), # eth / Twinkle - (1, b'\x24\x69\x27\x91\xbc\x44\x4c\x5c\xd0\xb8\x1e\x3c\xbc\xab\xa4\xb0\x4a\xcd\x1f\x3b', 'UKG', 18), # eth / UnikoinGold - (1, b'\x10\x5d\x97\xef\x2e\x72\x3f\x1c\xfb\x24\x51\x9b\xc6\xff\x15\xa6\xd0\x91\xa3\xf1', 'UMKA', 4), # eth / UMKA - (1, b'\x8e\x5a\xfc\x69\xf6\x22\x7a\x3a\xd7\x5e\xd3\x46\xc8\x72\x3b\xc6\x2c\xe9\x71\x23', 'UMKA', 4), # eth / UMKA - (1, b'\x89\x20\x5a\x3a\x3b\x2a\x69\xde\x6d\xbf\x7f\x01\xed\x13\xb2\x10\x8b\x2c\x43\xe7', 'Unicorn', 0), # eth / Unicorn - (1, b'\xd0\x1d\xb7\x3e\x04\x78\x55\xef\xb4\x14\xe6\x20\x20\x98\xc4\xbe\x4c\xd2\x42\x3b', 'UQC', 18), # eth / Uquid Coin - (1, b'\xd7\x60\xad\xdf\xb2\x4d\x9c\x01\xfe\x4b\xfe\xa7\x47\x5c\x5e\x36\x36\x68\x40\x58', 'USDM', 2), # eth / Mether (USDM) - (1, b'\xda\xc1\x7f\x95\x8d\x2e\xe5\x23\xa2\x20\x62\x06\x99\x45\x97\xc1\x3d\x83\x1e\xc7', 'USDT', 6), # eth / USD Tether (erc20) - (1, b'\x70\xa7\x28\x33\xd6\xbf\x7f\x50\x8c\x82\x24\xce\x59\xea\x1e\xf3\xd0\xea\x3a\x38', 'UTK', 18), # eth / UTK - (1, b'\x9e\x33\x19\x63\x6e\x21\x26\xe3\xc0\xbc\x9e\x31\x34\xae\xc5\xe1\x50\x8a\x46\xc7', 'UTN-P', 18), # eth / Universa - (1, b'\x35\x43\x63\x8e\xd4\xa9\x00\x6e\x48\x40\xb1\x05\x94\x42\x71\xbc\xea\x15\x60\x5d', 'UUU', 18), # eth / U Networks - (1, b'\x82\xbd\x52\x6b\xdb\x71\x8c\x6d\x4d\xd2\x29\x1e\xd0\x13\xa5\x18\x6c\xae\x2d\xca', 'VDOC', 18), # eth / Duty of Care Token - (1, b'\x34\x0d\x2b\xde\x5e\xb2\x8c\x1e\xed\x91\xb2\xf7\x90\x72\x3e\x3b\x16\x06\x13\xb7', 'VEE', 18), # eth / BLOCKv - (1, b'\xeb\xed\x4f\xf9\xfe\x34\x41\x3d\xb8\xfc\x82\x94\x55\x6b\xbd\x15\x28\xa4\xda\xca', 'VENUS', 3), # eth / VENUS - (1, b'\x8f\x34\x70\xa7\x38\x8c\x05\xee\x4e\x7a\xf3\xd0\x1d\x8c\x72\x2b\x0f\xf5\x23\x74', 'VERI', 18), # eth / Veritas - (1, b'\xd8\x50\x94\x2e\xf8\x81\x1f\x2a\x86\x66\x92\xa6\x23\x01\x1b\xde\x52\xa4\x62\xc1', 'VET', 18), # eth / Vechain - (1, b'\x2c\x97\x4b\x2d\x0b\xa1\x71\x6e\x64\x4c\x1f\xc5\x99\x82\xa8\x9d\xdd\x2f\xf7\x24', 'VIB', 18), # eth / VIB - (1, b'\x88\x24\x48\xf8\x3d\x90\xb2\xbf\x47\x7a\xf2\xea\x79\x32\x7f\xde\xa1\x33\x5d\x93', 'VIBEX', 18), # eth / VIBEX Exchange Token - (1, b'\xe8\xff\x5c\x9c\x75\xde\xb3\x46\xac\xac\x49\x3c\x46\x3c\x89\x50\xbe\x03\xdf\xba', 'VIBEX', 18), # eth / VIBEX - (1, b'\xf0\x3f\x8d\x65\xba\xfa\x59\x86\x11\xc3\x49\x51\x24\x09\x3c\x56\xe8\xf6\x38\xf0', 'VIEW', 18), # eth / Viewly - (1, b'\x23\xb7\x5b\xc7\xaa\xf2\x8e\x2d\x66\x28\xc3\xf4\x24\xb3\x88\x2f\x8f\x07\x2a\x3c', 'VIT', 18), # eth / Vice Industry Token - (1, b'\x51\x94\x75\xb3\x16\x53\xe4\x6d\x20\xcd\x09\xf9\xfd\xcf\x3b\x12\xbd\xac\xb4\xf5', 'VIU', 18), # eth / VIU - (1, b'\x92\x2a\xc4\x73\xa3\xcc\x24\x1f\xd3\xa0\x04\x9e\xd1\x45\x36\x45\x2d\x58\xd7\x3c', 'VLD', 18), # eth / VLD - (1, b'\xc3\xbc\x9e\xb7\x1f\x75\xec\x43\x9a\x6b\x6c\x8e\x8b\x74\x6f\xcf\x5b\x62\xf7\x03', 'VOC', 18), # eth / VORMACOIN - (1, b'\x83\xee\xa0\x0d\x83\x8f\x92\xde\xc4\xd1\x47\x56\x97\xb9\xf4\xd3\x53\x7b\x56\xe3', 'VOISE', 8), # eth / Voise - (1, b'\xed\xba\xf3\xc5\x10\x03\x02\xdc\xdd\xa5\x32\x69\x32\x2f\x37\x30\xb1\xf0\x41\x6d', 'VRS', 5), # eth / Veros - (1, b'\x5c\x54\x3e\x7a\xe0\xa1\x10\x4f\x78\x40\x6c\x34\x0e\x9c\x64\xfd\x9f\xce\x51\x70', 'VSL', 18), # eth / Vdice - (1, b'\x28\x6b\xda\x14\x13\xa2\xdf\x81\x73\x1d\x49\x30\xce\x2f\x86\x2a\x35\xa6\x09\xfe', 'WaBi', 18), # eth / WaBi - (1, b'\x39\xbb\x25\x9f\x66\xe1\xc5\x9d\x5a\xbe\xf8\x83\x75\x97\x9b\x4d\x20\xd9\x80\x22', 'WAX', 8), # eth / WAX - (1, b'\x74\x95\x1b\x67\x7d\xe3\x2d\x59\x6e\xe8\x51\xa2\x33\x33\x69\x26\xe6\xa2\xcd\x09', 'WBA', 7), # eth / WeBetCrypto - (1, b'\x8f\x93\x6f\xe0\xfa\xf0\x60\x4c\x9c\x0e\xf2\x40\x6b\xde\x0a\x65\x36\x55\x15\xd6', 'WCN', 18), # eth / WorldCoinNetwork - (1, b'\x6a\x0a\x97\xe4\x7d\x15\xaa\xd1\xd1\x32\xa1\xac\x79\xa4\x80\xe3\xf2\x07\x90\x63', 'WCT', 18), # eth / WePower - (1, b'\xc0\x2a\xaa\x39\xb2\x23\xfe\x8d\x0a\x0e\x5c\x4f\x27\xea\xd9\x08\x3c\x75\x6c\xc2', 'WETH', 18), # eth / WETH - (1, b'\xf4\xfe\x95\x60\x38\x81\xd0\xe0\x79\x54\xfd\x76\x05\xe0\xe9\xa9\x16\xe4\x2c\x44', 'WHEN', 18), # eth / WHEN Token - (1, b'\xe2\x00\x64\x18\x90\x77\x2f\xce\x8e\xe6\xed\xc5\x35\x4c\xce\xa3\x0a\xc9\x2f\x49', 'WHO', 18), # eth / WhoHas - (1, b'\xe9\x33\xc0\xcd\x97\x84\x41\x4d\x5f\x27\x8c\x11\x49\x04\xf5\xa8\x4b\x39\x69\x19', 'WHO', 18), # eth / WhoHas - (1, b'\x5e\x4a\xbe\x64\x19\x65\x0c\xa8\x39\xce\x5b\xb7\xdb\x42\x2b\x88\x1a\x60\x64\xbb', 'WiC', 18), # eth / Wi Coin - (1, b'\x62\xcd\x07\xd4\x14\xec\x50\xb6\x8c\x7e\xca\xa8\x63\xa2\x3d\x34\x4f\x2d\x06\x2f', 'WIC', 0), # eth / WickNote - (1, b'\xd3\xc0\x07\x72\xb2\x4d\x99\x7a\x81\x22\x49\xca\x63\x7a\x92\x1e\x81\x35\x77\x01', 'WILD', 18), # eth / WILD Token - (1, b'\x66\x70\x88\xb2\x12\xce\x3d\x06\xa1\xb5\x53\xa7\x22\x1e\x1f\xd1\x90\x00\xd9\xaf', 'WINGS', 18), # eth / WINGS - (1, b'\x72\x87\x81\xe7\x57\x35\xdc\x09\x62\xdf\x3a\x51\xd7\xef\x47\xe7\x98\xa7\x10\x7e', 'WOLK', 18), # eth / WOLK - (1, b'\xf6\xb5\x5a\xcb\xbc\x49\xf4\x52\x4a\xa4\x8d\x19\x28\x1a\x9a\x77\xc5\x4d\xe1\x0f', 'WOLK', 18), # eth / Wolk Token - (1, b'\xd1\x8e\x45\x4d\x84\x4e\xb0\x00\x9d\x32\xe0\x7a\x0c\xde\x89\xe1\x8d\x64\xcf\xb4', 'WORK', 18), # eth / workTOKEN - (1, b'\x62\x08\x72\x45\x08\x71\x25\xd3\xdb\x5b\x9a\x3d\x71\x3d\x78\xe7\xbb\xc3\x1e\x54', 'WPC', 18), # eth / WorldPeaceCoin - (1, b'\x4c\xf4\x88\x38\x7f\x03\x5f\xf0\x8c\x37\x15\x15\x56\x2c\xba\x71\x2f\x90\x15\xd4', 'WPR', 18), # eth / WePower Token - (1, b'\x71\xe8\xd7\x4f\xf1\xc9\x23\xe3\x69\xd0\xe7\x0d\xfb\x09\x86\x66\x29\xc4\xdd\x35', 'WRK', 18), # eth / WorkCoin - (1, b'\xb7\xcb\x1c\x96\xdb\x6b\x22\xb0\xd3\xd9\x53\x6e\x01\x08\xd0\x62\xbd\x48\x8f\x74', 'WTC', 18), # eth / Walton - (1, b'\xd8\x95\x0f\xde\xaa\x10\x30\x4b\x7a\x7f\xd0\x3a\x2f\xc6\x6b\xc3\x9f\x3c\x71\x1a', 'WYS', 18), # eth / wystoken - (1, b'\x05\x60\x17\xc5\x5a\xe7\xae\x32\xd1\x2a\xef\x7c\x67\x9d\xf8\x3a\x85\xca\x75\xff', 'WYV', 18), # eth / WyvernToken - (1, b'\x91\x0d\xfc\x18\xd6\xea\x3d\x6a\x71\x24\xa6\xf8\xb5\x45\x8f\x28\x10\x60\xfa\x4c', 'X8X', 18), # eth / X8X - (1, b'\x4d\xf8\x12\xf6\x06\x4d\xef\x1e\x5e\x02\x9f\x1c\xa8\x58\x77\x7c\xc9\x8d\x2d\x81', 'XAUR', 8), # eth / Xaurum - (1, b'\x28\xde\xe0\x1d\x53\xfe\xd0\xed\xf5\xf6\xe3\x10\xbf\x8e\xf9\x31\x15\x13\xae\x40', 'XBP', 18), # eth / BlitzPredict - (1, b'\x4d\x82\x9f\x8c\x92\xa6\x69\x1c\x56\x30\x0d\x02\x0c\x9e\x0d\xb9\x84\xcf\xe2\xba', 'XCC', 18), # eth / CoinCrowd - (1, b'\x16\xaf\x5b\xfb\x4a\xe7\xe4\x75\xb9\xad\xc3\xbf\x5c\xb2\xf1\xe6\xa5\x0d\x79\x40', 'XFS', 8), # eth / Fanship - (1, b'\xf6\xb6\xaa\x0e\xf0\xf5\xed\xc2\xc1\xc5\xd9\x25\x47\x7f\x97\xea\xf6\x63\x03\xe7', 'XGG', 8), # eth / Going Gems - (1, b'\x53\x3e\xf0\x98\x4b\x2f\xaa\x22\x7a\xcc\x62\x0c\x67\xcc\xe1\x2a\xa3\x9c\xd8\xcd', 'XGM', 8), # eth / XGM - (1, b'\x30\xf4\xa3\xe0\xab\x7a\x76\x73\x3d\x8b\x60\xb8\x9d\xd9\x3c\x3d\x0b\x4c\x9e\x2f', 'XGT', 18), # eth / XGT - (1, b'\xb1\x10\xec\x7b\x1d\xcb\x8f\xab\x8d\xed\xbf\x28\xf5\x3b\xc6\x3e\xa5\xbe\xdd\x84', 'XID', 8), # eth / XID - (1, b'\xbc\x86\x72\x7e\x77\x0d\xe6\x8b\x10\x60\xc9\x1f\x6b\xb6\x94\x5c\x73\xe1\x03\x88', 'XNK', 18), # eth / Ink Protocol - (1, b'\xab\x95\xe9\x15\xc1\x23\xfd\xed\x5b\xdf\xb6\x32\x5e\x35\xef\x55\x15\xf1\xea\x69', 'XNN', 18), # eth / XENON - (1, b'\x57\x2e\x6f\x31\x80\x56\xba\x0c\x5d\x47\xa4\x22\x65\x31\x13\x84\x3d\x25\x06\x91', 'XNT', 0), # eth / XNT - (1, b'\xb2\x47\x54\xbe\x79\x28\x15\x53\xdc\x1a\xdc\x16\x0d\xdf\x5c\xd9\xb7\x43\x61\xa4', 'XRL', 9), # eth / XRL - (1, b'\x0f\x51\x3f\xfb\x49\x26\xff\x82\xd7\xf6\x0a\x05\x06\x90\x47\xac\xa2\x95\xc4\x13', 'XSC', 18), # eth / XSC - (1, b'\x6f\x7a\x4b\xac\x33\x15\xb5\x08\x2f\x79\x31\x61\xa2\x2e\x26\x66\x6d\x22\x71\x7f', 'YEED', 18), # eth / YEED - (1, b'\x0f\x33\xbb\x20\xa2\x82\xa7\x64\x9c\x7b\x3a\xff\x64\x4f\x08\x4a\x93\x48\xe9\x33', 'YUPIE', 18), # eth / YUPIE - (1, b'\x67\x81\xa0\xf8\x4c\x7e\x9e\x84\x6d\xcb\x84\xa9\xa5\xbd\x49\x33\x30\x67\xb1\x04', 'ZAP', 18), # eth / ZAP - (1, b'\x7a\x41\xe0\x51\x7a\x5e\xca\x4f\xdb\xc7\xfb\xeb\xa4\xd4\xc4\x7b\x9f\xf6\xdc\x63', 'ZCS', 18), # eth / Zeusshield - (1, b'\x05\xf4\xa4\x2e\x25\x1f\x2d\x52\xb8\xed\x15\xe9\xfe\xda\xac\xfc\xef\x1f\xad\x27', 'ZIL', 12), # eth / Zilliqa - (1, b'\x55\x4f\xfc\x77\xf4\x25\x1a\x9f\xb3\xc0\xe3\x59\x0a\x6a\x20\x5f\x8d\x4e\x06\x7d', 'ZMN', 18), # eth / ZMINE - (1, b'\xe4\x1d\x24\x89\x57\x1d\x32\x21\x89\x24\x6d\xaf\xa5\xeb\xde\x1f\x46\x99\xf4\x98', 'ZRX', 18), # eth / 0x Project - (1, b'\xe3\x86\xb1\x39\xed\x37\x15\xca\x4b\x18\xfd\x52\x67\x1b\xdc\xea\x1c\xdf\xe4\xb1', 'ZST', 8), # eth / Zeus Exchange - (42, b'\x86\x67\x55\x92\x54\x24\x1d\xde\xd4\xd1\x13\x92\xf8\x68\xd7\x20\x92\x76\x53\x67', 'Aeternity', 18), # kov / Aeternity - (42, b'\x3c\x67\xf7\xd4\xde\xcf\x77\x95\x22\x5f\x51\xb5\x41\x34\xf8\x11\x37\x38\x5f\x83', 'GUP', 3), # kov / GUP - (4, b'\x39\x8a\x7a\x69\xf3\xc5\x91\x81\xa1\xff\xe3\x4b\xed\x11\xdc\xb5\xdf\x86\x3a\x8a', 'AETH', 18), # rin / AKASHA Tokens - (4, b'\xe2\x78\x26\xee\x77\x8b\x6f\x78\xa4\x9a\x68\x6d\xa7\xd6\x4f\x6e\x7b\x08\x4a\x4f', 'BHNT', 0), # rin / Berlin Hack&Tell winner token - (4, b'\x8b\x65\xd4\xb7\xee\x3f\xff\xa9\x86\xc5\x77\xf0\xf4\xb7\x0a\x21\xba\xe3\xdd\x54', 'CTGA', 18), # rin / Convenient To Go - (4, b'\x27\x5a\x5b\x34\x65\x99\xb5\x69\x17\xe7\xb1\xc9\xde\x01\x9d\xcf\x9e\xad\x86\x1a', 'KC', 18), # rin / Karma Token - (4, b'\x64\x75\xa7\xfa\x6e\xd2\xd5\x18\x0f\x0e\x0a\x07\xc2\xd9\x51\xd1\x2c\x0e\xdb\x91', 'NONE', 0), # rin / None - (4, b'\x12\xfe\x17\x4c\x09\x7f\x6b\x3e\x87\x6b\x3b\x06\x0c\x90\x61\xf4\xb9\xde\xbb\x80', 'PPD', 18), # rin / PP Donation - (4, b'\x0a\x05\x7a\x87\xce\x9c\x56\xd7\xe3\x36\xb4\x17\xc7\x9c\xf3\x0e\x8d\x27\x86\x0b', 'WALL', 15), # rin / WALLETH Community-Token - (3, b'\x6f\x95\xa3\xb6\x82\xf8\xe9\xaa\xcc\x86\xd0\x57\xa6\xdf\x88\xa0\xe6\x81\x45\xa8', 'ILSC', 2), # rop / IsraCoin - (3, b'\xfd\x5a\x69\xa1\x30\x95\x95\xff\x51\x21\x55\x3f\x52\xc8\xa5\xb2\xb1\xb3\x10\x31', 'NONE', 0), # rop / None - (8, b'\xff\x3b\xf0\x57\xad\xf3\xb0\xe0\x15\xb6\x46\x53\x31\xa6\x23\x6e\x55\x68\x82\x74', 'BEER', 0), # ubq / BEER - (8, b'\x08\x53\x3d\x6a\x06\xce\x36\x52\x98\xb1\x2e\xf9\x2e\xb4\x07\xcb\xa8\xaa\x82\x73', 'CEFS', 8), # ubq / CEFS - (8, b'\x94\xad\x7e\x41\xc1\xd4\x40\x22\xc4\xf4\x7c\xb1\xba\x01\x9f\xd1\xa0\x22\xc5\x36', 'DOT', 8), # ubq / DOT - (8, b'\x4b\x48\x99\xa1\x0f\x3e\x50\x7d\xb2\x07\xb0\xee\x24\x26\x02\x9e\xfa\x16\x8a\x67', 'QWARK', 8), # ubq / QWARK - (8, b'\x5e\x17\x15\xbb\x79\x80\x5b\xd6\x72\x72\x97\x60\xb3\xf7\xf3\x4d\x6f\x48\x50\x98', 'RICKS', 8), # ubq / RICKS + ( + 64, + b"\x99\x1e\x7f\xe4\xb0\x5f\x2b\x3d\xb1\xd7\x88\xe7\x05\x96\x3f\x5d\x64\x7b\x00\x44", + "MINING", + 18, + ), # ella / Ella Mining Tokens + ( + 61, + b"\x08\x5f\xb4\xf2\x40\x31\xea\xed\xbc\x2b\x61\x1a\xa5\x28\xf2\x23\x43\xeb\x52\xdb", + "BEC", + 8, + ), # etc / BEC + ( + 61, + b"\x5a\xce\x17\xf8\x7c\x73\x91\xe5\x79\x2a\x76\x83\x06\x9a\x80\x25\xb8\x3b\xbd\x85", + "PLAY", + 0, + ), # etc / Smart Billions + ( + 1, + b"\x4e\x84\xe9\xe5\xfb\x0a\x97\x26\x28\xcf\x45\x68\xc4\x03\x16\x7e\xf1\xd4\x04\x31", + "$FFC", + 18, + ), # eth / $Fluzcoin + ( + 1, + b"\xa0\x24\xe8\x05\x7e\xec\x47\x4a\x9b\x23\x56\x83\x37\x07\xdd\x05\x79\xe2\x6e\xf3", + "$FXY", + 18, + ), # eth / $FIXY NETWORK + ( + 1, + b"\x7d\xd7\xf5\x6d\x69\x7c\xc0\xf2\xb5\x2b\xd5\x5c\x05\x7f\x37\x8f\x1f\xe6\xab\x4b", + "$TEAK", + 18, + ), # eth / $TEAK + ( + 1, + b"\xb6\xed\x76\x44\xc6\x94\x16\xd6\x7b\x52\x2e\x20\xbc\x29\x4a\x9a\x9b\x40\x5b\x31", + "0xBTC", + 8, + ), # eth / 0xBitcoin + ( + 1, + b"\xaf\x30\xd2\xa7\xe9\x0d\x7d\xc3\x61\xc8\xc4\x58\x5e\x9b\xb7\xd2\xf6\xf1\x5b\xc7", + "1ST", + 18, + ), # eth / FirstBlood + ( + 1, + b"\xfd\xbc\x1a\xdc\x26\xf0\xf8\xf8\x60\x6a\x5d\x63\xb7\xd3\xa3\xcd\x21\xc2\x2b\x23", + "1WO", + 8, + ), # eth / 1WO + ( + 1, + b"\x9f\xc0\x58\x32\x20\xeb\x44\xfa\xee\x9e\x2d\xc1\xe6\x3f\x39\x20\x4d\xdd\x90\x90", + "2DC", + 18, + ), # eth / DualChain + ( + 1, + b"\xae\xc9\x8a\x70\x88\x10\x41\x48\x78\xc3\xbc\xdf\x46\xaa\xd3\x1d\xed\x4a\x45\x57", + "300", + 18, + ), # eth / 300 Token Sparta + ( + 1, + b"\xbd\xe8\xf7\x82\x0b\x55\x44\xa4\x9d\x34\xf9\xdd\xea\xca\xbe\xdc\x7c\x0b\x5a\xdc", + "A18", + 0, + ), # eth / Apollo18 + ( + 1, + b"\xb9\x8d\x4c\x97\x42\x5d\x99\x08\xe6\x6e\x53\xa6\xfd\xf6\x73\xac\xca\x0b\xe9\x86", + "ABT", + 18, + ), # eth / ArcBlock Token + ( + 1, + b"\x0e\x8d\x6b\x47\x1e\x33\x2f\x14\x0e\x7d\x9d\xbb\x99\xe5\xe3\x82\x2f\x72\x8d\xa6", + "ABYSS", + 18, + ), # eth / ABYSS + ( + 1, + b"\x13\xf1\xb7\xfd\xfb\xe1\xfc\x66\x67\x6d\x56\x48\x3e\x21\xb1\xec\xb4\x0b\x58\xe2", + "ACC", + 18, + ), # eth / Accelerator Network + ( + 1, + b"\xe6\x9a\x35\x3b\x31\x52\xdd\x7b\x70\x6f\xf7\xdd\x40\xfe\x1d\x18\xb7\x80\x2d\x31", + "ADH", + 18, + ), # eth / AdHive Token + ( + 1, + b"\x88\x10\xc6\x34\x70\xd3\x86\x39\x95\x4c\x6b\x41\xaa\xc5\x45\x84\x8c\x46\x48\x4a", + "ADI", + 18, + ), # eth / Aditus + ( + 1, + b"\x66\x0e\x71\x48\x37\x85\xf6\x61\x33\x54\x8b\x10\xf6\x92\x6d\xc3\x32\xb0\x6e\x61", + "ADL", + 18, + ), # eth / Adelphoi + ( + 1, + b"\x42\x28\x66\xa8\xf0\xb0\x32\xc5\xcf\x1d\xfb\xde\xf3\x1a\x20\xf4\x50\x95\x62\xb0", + "ADST", + 0, + ), # eth / AdShares + ( + 1, + b"\xd0\xd6\xd6\xc5\xfe\x4a\x67\x7d\x34\x3c\xc4\x33\x53\x6b\xb7\x17\xba\xe1\x67\xdd", + "ADT", + 9, + ), # eth / AdToken + ( + 1, + b"\x44\x70\xbb\x87\xd7\x7b\x96\x3a\x01\x3d\xb9\x39\xbe\x33\x2f\x92\x7f\x2b\x99\x2e", + "ADX", + 4, + ), # eth / AdEx Network + ( + 1, + b"\x5c\xa9\xa7\x1b\x1d\x01\x84\x9c\x0a\x95\x49\x0c\xc0\x05\x59\x71\x7f\xcf\x0d\x1d", + "AE", + 18, + ), # eth / aeternity + ( + 1, + b"\x8e\xb2\x43\x19\x39\x37\x16\x66\x8d\x76\x8d\xce\xc2\x93\x56\xae\x9c\xff\xe2\x85", + "AGI", + 8, + ), # eth / SingularityNET + ( + 1, + b"\x4c\xed\xa7\x90\x6a\x5e\xd2\x17\x97\x85\xcd\x3a\x40\xa6\x9e\xe8\xbc\x99\xc4\x66", + "AION", + 8, + ), # eth / Aion + ( + 1, + b"\x27\xdc\xe1\xec\x4d\x3f\x72\xc3\xe4\x57\xcc\x50\x35\x4f\x1f\x97\x5d\xde\xf4\x88", + "AIR", + 8, + ), # eth / AirToken + ( + 1, + b"\x10\x63\xce\x52\x42\x65\xd5\xa3\xa6\x24\xf4\x91\x4a\xcd\x57\x3d\xd8\x9c\xe9\x88", + "AIX", + 18, + ), # eth / Aigang + ( + 1, + b"\x18\x1a\x63\x74\x6d\x3a\xdc\xf3\x56\xcb\xc7\x3a\xce\x22\x83\x2f\xfb\xb1\xee\x5a", + "ALCO", + 8, + ), # eth / ALCO + ( + 1, + b"\xea\x61\x0b\x11\x53\x47\x77\x20\x74\x8d\xc1\x3e\xd3\x78\x00\x39\x41\xd8\x4f\xab", + "ALIS", + 18, + ), # eth / ALIS Token + ( + 1, + b"\x63\x8a\xc1\x49\xea\x8e\xf9\xa1\x28\x6c\x41\xb9\x77\x01\x7a\xa7\x35\x9e\x6c\xfa", + "ALTS", + 18, + ), # eth / ALTS Token + ( + 1, + b"\x4d\xc3\x64\x3d\xbc\x64\x2b\x72\xc1\x58\xe7\xf3\xd2\xff\x23\x2d\xf6\x1c\xb6\xce", + "AMB", + 18, + ), # eth / Amber Token + ( + 1, + b"\x94\x9b\xed\x88\x6c\x73\x9f\x1a\x32\x73\x62\x9b\x33\x20\xdb\x0c\x50\x24\xc7\x19", + "AMIS", + 9, + ), # eth / AMIS + ( + 1, + b"\x73\x7f\x98\xac\x8c\xa5\x9f\x2c\x68\xad\x65\x8e\x3c\x3d\x8c\x89\x63\xe4\x0a\x4c", + "AMN", + 18, + ), # eth / Amon + ( + 1, + b"\x38\xc8\x7a\xa8\x9b\x2b\x8c\xd9\xb9\x5b\x73\x6e\x1f\xa7\xb6\x12\xea\x97\x21\x69", + "AMO", + 18, + ), # eth / AMO Coin + ( + 1, + b"\x84\x93\x6c\xf7\x63\x0a\xa3\xe2\x7d\xd9\xaf\xf9\x68\xb1\x40\xd5\xae\xe4\x9f\x5a", + "AMTC", + 8, + ), # eth / AmberTime Coin + ( + 1, + b"\x96\x0b\x23\x6a\x07\xcf\x12\x26\x63\xc4\x30\x33\x50\x60\x9a\x66\xa7\xb2\x88\xc0", + "ANT", + 18, + ), # eth / ANT + ( + 1, + b"\x4c\x0f\xbe\x1b\xb4\x66\x12\x91\x5e\x79\x67\xd2\xc3\x21\x3c\xd4\xd8\x72\x57\xad", + "APIS", + 18, + ), # eth / APIS + ( + 1, + b"\x1a\x7a\x8b\xd9\x10\x6f\x2b\x8d\x97\x7e\x08\x58\x2d\xc7\xd2\x4c\x72\x3a\xb0\xdb", + "APPC", + 18, + ), # eth / AppCoins + ( + 1, + b"\x23\xae\x3c\x5b\x39\xb1\x2f\x06\x93\xe0\x54\x35\xee\xaa\x1e\x51\xd8\xc6\x15\x30", + "APT", + 18, + ), # eth / AIGang + ( + 1, + b"\xac\x70\x9f\xcb\x44\xa4\x3c\x35\xf0\xda\x4e\x31\x63\xb1\x17\xa1\x7f\x37\x70\xf5", + "ARC", + 18, + ), # eth / ARC + ( + 1, + b"\x12\x45\xef\x80\xf4\xd9\xe0\x2e\xd9\x42\x53\x75\xe8\xf6\x49\xb9\x22\x1b\x31\xd8", + "ARCT", + 8, + ), # eth / ArbitrageCT + ( + 1, + b"\x75\xaa\x7b\x0d\x02\x53\x2f\x38\x33\xb6\x6c\x7f\x0a\xd3\x53\x76\xd3\x73\xdd\xf8", + "ARD", + 18, + ), # eth / Accord + ( + 1, + b"\xba\x5f\x11\xb1\x6b\x15\x57\x92\xcf\x3b\x2e\x68\x80\xe8\x70\x68\x59\xa8\xae\xb6", + "ARN", + 8, + ), # eth / Aeron Token + ( + 1, + b"\xfe\xc0\xcf\x7f\xe0\x78\xa5\x00\xab\xf1\x5f\x12\x84\x95\x8f\x22\x04\x9c\x2c\x7e", + "ART", + 18, + ), # eth / ART + ( + 1, + b"\x77\x05\xfa\xa3\x4b\x16\xeb\x6d\x77\xdf\xc7\x81\x2b\xe2\x36\x7b\xa6\xb0\x24\x8e", + "ARX", + 8, + ), # eth / ARX + ( + 1, + b"\xb0\xd9\x26\xc1\xbc\x3d\x78\x06\x4f\x3e\x10\x75\xd5\xbd\x9a\x24\xf3\x5a\xe6\xc5", + "ARXT", + 18, + ), # eth / Assistive Reality ARX + ( + 1, + b"\x27\x05\x4b\x13\xb1\xb7\x98\xb3\x45\xb5\x91\xa4\xd2\x2e\x65\x62\xd4\x7e\xa7\x5a", + "AST", + 4, + ), # eth / Airswap + ( + 1, + b"\x17\x05\x2d\x51\xe9\x54\x59\x2c\x10\x46\x32\x0c\x23\x71\xab\xab\x6c\x73\xef\x10", + "ATH", + 18, + ), # eth / Athenian Warrior Token + ( + 1, + b"\x15\x43\xd0\xf8\x34\x89\xe8\x2a\x13\x44\xdf\x68\x27\xb2\x3d\x54\x1f\x23\x5a\x50", + "ATH (AIgatha Token)", + 18, + ), # eth / AIgatha Token + ( + 1, + b"\x78\xb7\xfa\xda\x55\xa6\x4d\xd8\x95\xd8\xc8\xc3\x57\x79\xdd\x8b\x67\xfa\x8a\x05", + "ATL", + 18, + ), # eth / ATL + ( + 1, + b"\x97\xae\xb5\x06\x6e\x1a\x59\x0e\x86\x8b\x51\x14\x57\xbe\xb6\xfe\x99\xd3\x29\xf5", + "ATMI", + 18, + ), # eth / Atonomi + ( + 1, + b"\x88\x78\x34\xd3\xb8\xd4\x50\xb6\xba\xb1\x09\xc2\x52\xdf\x3d\xa2\x86\xd7\x3c\xe4", + "ATT", + 18, + ), # eth / Atmatrix Token + ( + 1, + b"\x63\x39\x78\x4d\x94\x78\xda\x43\x10\x6a\x42\x91\x96\x77\x2a\x02\x9c\x2f\x17\x7d", + "ATTN", + 18, + ), # eth / Attention Token + ( + 1, + b"\xed\x24\x79\x80\x39\x6b\x10\x16\x9b\xb1\xd3\x6f\x6e\x27\x8e\xd1\x67\x00\xa6\x0f", + "AVA", + 4, + ), # eth / AVA + ( + 1, + b"\x0d\x88\xed\x6e\x74\xbb\xfd\x96\xb8\x31\x23\x16\x38\xb6\x6c\x05\x57\x1e\x82\x4f", + "AVT", + 18, + ), # eth / AVT + ( + 1, + b"\xcd\x4b\x4b\x0f\x32\x84\xa3\x3a\xc4\x9c\x67\x96\x1e\xc6\xe1\x11\x70\x83\x18\xcf", + "AX1", + 5, + ), # eth / AX1 Mining Token + ( + 1, + b"\x9a\xf2\xc6\xb1\xa2\x8d\x3d\x6b\xc0\x84\xbd\x26\x7f\x70\xe9\x0d\x49\x74\x1d\x5b", + "AXP", + 8, + ), # eth / AXP + ( + 1, + b"\xf8\x7f\x0d\x91\x53\xfe\xa5\x49\xc7\x28\xad\x61\xcb\x80\x15\x95\xa6\x8b\x73\xde", + "BANX", + 18, + ), # eth / BANX + ( + 1, + b"\x0d\x87\x75\xf6\x48\x43\x06\x79\xa7\x09\xe9\x8d\x2b\x0c\xb6\x25\x0d\x28\x87\xef", + "BAT", + 18, + ), # eth / BAT + ( + 1, + b"\x4a\x60\x58\x66\x6c\xf1\x05\x7e\xac\x3c\xd3\xa5\xa6\x14\x62\x05\x47\x55\x9f\xc9", + "BBK", + 18, + ), # eth / BRICKBLOCK TOKEN + ( + 1, + b"\x73\x67\xa6\x80\x39\xd4\x70\x4f\x30\xbf\xbf\x6d\x94\x80\x20\xc3\xb0\x7d\xfc\x59", + "BCBC", + 18, + ), # eth / Beercoin + ( + 1, + b"\x1e\x79\x7c\xe9\x86\xc3\xcf\xf4\x47\x2f\x7d\x38\xd5\xc4\xab\xa5\x5d\xfe\xfe\x40", + "BCDN", + 15, + ), # eth / BCDN + ( + 1, + b"\xac\xfa\x20\x9f\xb7\x3b\xf3\xdd\x5b\xbf\xb1\x10\x1b\x9b\xc9\x99\xc4\x90\x62\xa5", + "BCDT", + 18, + ), # eth / Blockchain Certified Data Token + ( + 1, + b"\xbc\x12\x34\x55\x2e\xbe\xa3\x2b\x51\x21\x19\x03\x56\xbb\xa6\xd3\xbb\x22\x5b\xb5", + "BCL", + 18, + ), # eth / BCL + ( + 1, + b"\x1c\x44\x81\x75\x0d\xaa\x5f\xf5\x21\xa2\xa7\x49\x0d\x99\x81\xed\x46\x46\x5d\xbd", + "BCPT", + 18, + ), # eth / BCPT + ( + 1, + b"\x10\x14\x61\x3e\x2b\x3c\xbc\x4d\x57\x50\x54\xd4\x98\x2e\x58\x0d\x9b\x99\xd7\xb1", + "BCV", + 8, + ), # eth / BitCapitalVendor Token + ( + 1, + b"\x19\x61\xb3\x33\x19\x69\xed\x52\x77\x07\x51\xfc\x71\x8e\xf5\x30\x83\x8b\x6d\xee", + "BDG", + 18, + ), # eth / BitDegree Token + ( + 1, + b"\x4d\x8f\xc1\x45\x3a\x0f\x35\x9e\x99\xc9\x67\x59\x54\xe6\x56\xd8\x0d\x99\x6f\xbf", + "BEE", + 18, + ), # eth / Bee Token + ( + 1, + b"\x74\xc1\xe4\xb8\xca\xe5\x92\x69\xec\x1d\x85\xd3\xd4\xf3\x24\x39\x60\x48\xf4\xac", + "BeerCoin", + 0, + ), # eth / BeerCoin + ( + 1, + b"\x6a\xeb\x95\xf0\x6c\xda\x84\xca\x34\x5c\x2d\xe0\xf3\xb7\xf9\x69\x23\xa4\x4f\x4c", + "BERRY", + 14, + ), # eth / Berry + ( + 1, + b"\x8a\xa3\x3a\x78\x99\xfc\xc8\xea\x5f\xbe\x6a\x60\x8a\x10\x9c\x38\x93\xa1\xb8\xb2", + "BET", + 18, + ), # eth / BET + ( + 1, + b"\x76\x31\x86\xeb\x8d\x48\x56\xd5\x36\xed\x44\x78\x30\x29\x71\x21\x4f\xeb\xc6\xa9", + "BETR", + 18, + ), # eth / BETR + ( + 1, + b"\xb2\xbf\xeb\x70\xb9\x03\xf1\xba\xac\x7f\x2b\xa2\xc6\x29\x34\xc7\xe5\xb9\x74\xc4", + "BKB", + 8, + ), # eth / BetKing Bankroll Token + ( + 1, + b"\x3c\xf9\xe0\xc3\x85\xa5\xab\xec\x9f\xd2\xa7\x17\x90\xaa\x34\x4c\x4e\x8e\x35\x70", + "BKRx", + 18, + ), # eth / BlockRx + ( + 1, + b"\x45\x24\x5b\xc5\x92\x19\xee\xaa\xf6\xcd\x3f\x38\x2e\x07\x8a\x46\x1f\xf9\xde\x7b", + "BKX", + 18, + ), # eth / BANKEX + ( + 1, + b"\x10\x7c\x45\x04\xcd\x79\xc5\xd2\x69\x6e\xa0\x03\x0a\x8d\xd4\xe9\x26\x01\xb8\x2e", + "BLT", + 18, + ), # eth / Bloom + ( + 1, + b"\x53\x9e\xfe\x69\xbc\xdd\x21\xa8\x3e\xfd\x91\x22\x57\x1a\x64\xcc\x25\xe0\x28\x2b", + "BLUE", + 8, + ), # eth / Ethereum Blue + ( + 1, + b"\xce\x59\xd2\x9b\x09\xaa\xe5\x65\xfe\xee\xf8\xe5\x2f\x47\xc3\xcd\x53\x68\xc6\x63", + "BLX (Bullion)", + 18, + ), # eth / Bullion Crypto + ( + 1, + b"\xe5\xa7\xc1\x29\x72\xf3\xbb\xfe\x70\xed\x29\x52\x1c\x89\x49\xb8\xaf\x6a\x09\x70", + "BLX (Iconomi)", + 18, + ), # eth / Iconomi + ( + 1, + b"\x57\x32\x04\x6a\x88\x37\x04\x40\x4f\x28\x4c\xe4\x1f\xfa\xdd\x5b\x00\x7f\xd6\x68", + "BLZ", + 18, + ), # eth / Bluezelle + ( + 1, + b"\xdf\x6e\xf3\x43\x35\x07\x80\xbf\x8c\x34\x10\xbf\x06\x2e\x0c\x01\x5b\x1d\xd6\x71", + "BMC", + 8, + ), # eth / Blackmoon Crypto BMC Token + ( + 1, + b"\xf0\x28\xad\xee\x51\x53\x3b\x1b\x47\xbe\xaa\x89\x0f\xeb\x54\xa4\x57\xf5\x1e\x89", + "BMT", + 18, + ), # eth / BMT + ( + 1, + b"\x98\x6e\xe2\xb9\x44\xc4\x2d\x01\x7f\x52\xaf\x21\xc4\xc6\x9b\x84\xdb\xea\x35\xd8", + "BMX", + 18, + ), # eth / BitMartToken + ( + 1, + b"\xb8\xc7\x74\x82\xe4\x5f\x1f\x44\xde\x17\x45\xf5\x2c\x74\x42\x6c\x63\x1b\xdd\x52", + "BNB", + 18, + ), # eth / BNB + ( + 1, + b"\xdd\x6b\xf5\x6c\xa2\xad\xa2\x4c\x68\x3f\xac\x50\xe3\x77\x83\xe5\x5b\x57\xaf\x9f", + "BNC", + 12, + ), # eth / BNC + ( + 1, + b"\xda\x2c\x42\x4f\xc9\x8c\x74\x1c\x2d\x4e\xf2\xf4\x28\x97\xce\xfe\xd8\x97\xca\x75", + "BNFT", + 9, + ), # eth / Benefits Coin + ( + 1, + b"\x1f\x57\x3d\x6f\xb3\xf1\x3d\x68\x9f\xf8\x44\xb4\xce\x37\x79\x4d\x79\xa7\xff\x1c", + "BNT", + 18, + ), # eth / Bancor + ( + 1, + b"\xd2\xd6\x15\x86\x83\xae\xe4\xcc\x83\x80\x67\x72\x72\x09\xa0\xaa\xf4\x35\x9d\xe3", + "BNTY", + 18, + ), # eth / Bounty0x Token + ( + 1, + b"\xdf\x34\x79\x11\x91\x0b\x6c\x9a\x42\x86\xba\x8e\x2e\xe5\xea\x4a\x39\xeb\x21\x34", + "BOB", + 18, + ), # eth / Bob's repair + ( + 1, + b"\xcc\x34\x36\x6e\x38\x42\xca\x1b\xd3\x6c\x1f\x32\x4d\x15\x25\x79\x60\xfc\xc8\x01", + "BON", + 18, + ), # eth / Bonpay + ( + 1, + b"\x7f\x1e\x2c\x7d\x6a\x69\xbf\x34\x82\x4d\x72\xc5\x3b\x45\x50\xe8\x95\xc0\xd8\xc2", + "BOP", + 8, + ), # eth / BlockOptiopns Token + ( + 1, + b"\xc2\xc6\x3f\x23\xec\x5e\x97\xef\xbd\x75\x65\xdf\x9e\xc7\x64\xfd\xc7\xd4\xe9\x1d", + "BOU", + 18, + ), # eth / Boule Coin + ( + 1, + b"\x32\x76\x82\x77\x9b\xab\x2b\xf4\xd1\x33\x7e\x89\x74\xab\x9d\xe8\x27\x5a\x7c\xa8", + "BPT", + 18, + ), # eth / Blockport Token + ( + 1, + b"\x5a\xf2\xbe\x19\x3a\x6a\xbc\xa9\xc8\x81\x70\x01\xf4\x57\x44\x77\x7d\xb3\x07\x56", + "BQX", + 8, + ), # eth / Bitquence + ( + 1, + b"\x9e\x77\xd5\xa1\x25\x1b\x6f\x7d\x45\x67\x22\xa6\xea\xc6\xd2\xd5\x98\x0b\xd8\x91", + "BRAT", + 8, + ), # eth / BRAT + ( + 1, + b"\x55\x8e\xc3\x15\x2e\x2e\xb2\x17\x49\x05\xcd\x19\xae\xa4\xe3\x4a\x23\xde\x9a\xd6", + "BRD", + 18, + ), # eth / Bread + ( + 1, + b"\xf2\x6e\xf5\xe0\x54\x53\x84\xb7\xdc\xc0\xf2\x97\xf2\x67\x41\x89\x58\x68\x30\xdf", + "BSDC", + 18, + ), # eth / BSDC + ( + 1, + b"\x50\x9a\x38\xb7\xa1\xcc\x0d\xcd\x83\xaa\x9d\x06\x21\x46\x63\xd9\xec\x7c\x7f\x4a", + "BST", + 18, + ), # eth / BlocksquareToken + ( + 1, + b"\x08\x86\x94\x9c\x1b\x8c\x41\x28\x60\xc4\x26\x4c\xeb\x80\x83\xd1\x36\x5e\x86\xcf", + "BTCE", + 8, + ), # eth / EthereumBitcoin + ( + 1, + b"\x5a\xcd\x19\xb9\xc9\x1e\x59\x6b\x1f\x06\x2f\x18\xe3\xd0\x2d\xa7\xed\x8d\x1e\x50", + "BTCL", + 8, + ), # eth / BTC Lite + ( + 1, + b"\x73\xdd\x06\x9c\x29\x9a\x5d\x69\x1e\x98\x36\x24\x3b\xca\xec\x9c\x8c\x1d\x87\x34", + "BTE", + 8, + ), # eth / BTE + ( + 1, + b"\xfa\xd5\x72\xdb\x56\x6e\x52\x34\xac\x9f\xc3\xd5\x70\xc4\xed\xc0\x05\x0e\xaa\x92", + "BTH", + 18, + ), # eth / Bytether + ( + 1, + b"\xa0\x2e\x3b\xb9\xce\xbc\x03\x95\x26\x01\xb3\x72\x4b\x49\x40\xe0\x84\x5b\xeb\xcf", + "BTHR", + 18, + ), # eth / Bethereum + ( + 1, + b"\xdb\x86\x46\xf5\xb4\x87\xb5\xdd\x97\x9f\xac\x61\x83\x50\xe8\x50\x18\xf5\x57\xd4", + "BTK", + 18, + ), # eth / Bitcoin Token + ( + 1, + b"\x2a\xcc\xab\x9c\xb7\xa4\x8c\x3e\x82\x28\x6f\x0b\x2f\x87\x98\xd2\x01\xf4\xec\x3f", + "BTL (Battle)", + 18, + ), # eth / BTL (Battle) + ( + 1, + b"\x92\x68\x5e\x93\x95\x65\x37\xc2\x5b\xb7\x5d\x5d\x47\xfc\xa4\x26\x6d\xd6\x28\xb8", + "BTL (Bitlle)", + 4, + ), # eth / Bitlle Token + ( + 1, + b"\xcb\x97\xe6\x5f\x07\xda\x24\xd4\x6b\xcd\xd0\x78\xeb\xeb\xd7\xc6\xe6\xe3\xd7\x50", + "BTM", + 8, + ), # eth / Bytom + ( + 1, + b"\x16\xb0\xe6\x2a\xc1\x3a\x2f\xae\xd3\x6d\x18\xbc\xe2\x35\x6d\x25\xab\x3c\xfa\xd3", + "BTQ", + 18, + ), # eth / Bitcoin Boutique + ( + 1, + b"\x08\x0a\xa0\x7e\x2c\x71\x85\x15\x0d\x7e\x4d\xa9\x88\x38\xa8\xd2\xfe\xac\x3d\xfc", + "BTT", + 0, + ), # eth / Bitether + ( + 1, + b"\xfa\x45\x6c\xf5\x52\x50\xa8\x39\x08\x8b\x27\xee\x32\xa4\x24\xd7\xda\xcb\x54\xff", + "BTTX", + 18, + ), # eth / Blocktrade.com + ( + 1, + b"\xca\x3c\x18\xa6\x5b\x80\x2e\xc2\x67\xf8\xf4\x80\x25\x45\xe7\xf5\x3d\x24\xc7\x5e", + "BUC", + 18, + ), # eth / BeeUnity Chain + ( + 1, + b"\x26\xe7\x53\x07\xfc\x0c\x02\x14\x72\xfe\xb8\xf7\x27\x83\x95\x31\xf1\x12\xf3\x17", + "C20", + 18, + ), # eth / Crypto20's Token + ( + 1, + b"\xd4\x2d\xeb\xe4\xed\xc9\x2b\xd5\xa3\xfb\xb4\x24\x3e\x1e\xcc\xf6\xd6\x3a\x4a\x5d", + "C8", + 18, + ), # eth / Carboneum + ( + 1, + b"\x7d\x4b\x8c\xce\x05\x91\xc9\x04\x4a\x22\xee\x54\x35\x33\xb7\x2e\x97\x6e\x36\xc3", + "CAG", + 18, + ), # eth / Change Bank + ( + 1, + b"\x1d\x46\x24\x14\xfe\x14\xcf\x48\x9c\x7a\x21\xca\xc7\x85\x09\xf4\xbf\x8c\xd7\xc0", + "CAN", + 6, + ), # eth / CAN + ( + 1, + b"\x42\x3e\x43\x22\xcd\xda\x29\x15\x6b\x49\xa1\x7d\xfb\xd2\xac\xc4\xb2\x80\x60\x0d", + "CAR", + 9, + ), # eth / Car Sharing Community + ( + 1, + b"\xa5\x17\xa4\x6b\xaa\xd6\xb0\x54\xa7\x6b\xd1\x9c\x46\x84\x4f\x71\x7f\xe6\x9f\xea", + "CARB", + 8, + ), # eth / CarbCoin + ( + 1, + b"\x21\x08\xe6\x2d\x33\x5b\xbd\xc8\x9e\xc3\xe9\xd8\x58\x2f\x18\xdc\xfb\x0c\xdf\xf4", + "CARCO", + 8, + ), # eth / CARCO + ( + 1, + b"\x1e\xd2\xb1\xea\xed\x8e\x96\x8b\xc3\x6e\xb9\x0a\x91\x46\x60\xa7\x18\x27\xa5\xe9", + "CARD", + 0, + ), # eth / Cardstack Token + ( + 1, + b"\xbf\x18\xf2\x46\xb9\x30\x1f\x23\x1e\x95\x61\xb3\x5a\x38\x79\x76\x9b\xb4\x63\x75", + "CARE", + 18, + ), # eth / Token CARE + ( + 1, + b"\xe8\x78\x0b\x48\xbd\xb0\x5f\x92\x86\x97\xa5\xe8\x15\x5f\x67\x2e\xd9\x14\x62\xf7", + "CAS", + 18, + ), # eth / Cashaa + ( + 1, + b"\x12\x34\x56\x74\x61\xd3\xf8\xdb\x74\x96\x58\x17\x74\xbd\x86\x9c\x83\xd5\x1c\x93", + "CAT (BitClave)", + 18, + ), # eth / CAT (BitClave) + ( + 1, + b"\x56\xba\x2e\xe7\x89\x04\x61\xf4\x63\xf7\xbe\x02\xaa\xc3\x09\x9f\x6d\x58\x11\xa8", + "CAT (Blockcat)", + 18, + ), # eth / CAT (Blockcat) + ( + 1, + b"\x68\xe1\x4b\xb5\xa4\x5b\x96\x81\x32\x7e\x16\xe5\x28\x08\x4b\x9d\x96\x2c\x1a\x39", + "CATs (BitClave)_Old", + 18, + ), # eth / CATs (BitClave)_Old + ( + 1, + b"\xc1\x66\x03\x87\x05\xff\xba\xb3\x79\x41\x85\xb3\xa9\xd9\x25\x63\x2a\x1d\xf3\x7d", + "CC3", + 18, + ), # eth / Coal Coin + ( + 1, + b"\x28\x57\x7a\x6d\x31\x55\x9b\xd2\x65\xce\x3a\xdb\x62\xd0\x45\x85\x50\xf7\xb8\xa7", + "CCC (CryptoCrashCourse)", + 18, + ), # eth / CryptoCrashCourse + ( + 1, + b"\xbe\x11\xee\xb1\x86\xe6\x24\xb8\xf2\x6a\x50\x45\x57\x5a\x13\x40\xe4\x05\x45\x52", + "CCC (ICONOMI)", + 18, + ), # eth / CCC (ICONOMI) + ( + 1, + b"\xd3\x48\xe0\x7a\x28\x06\x50\x5b\x85\x61\x23\x04\x5d\x27\xae\xed\x90\x92\x4b\x50", + "CCLC", + 8, + ), # eth / Christ Coin + ( + 1, + b"\x31\x5c\xe5\x9f\xaf\xd3\xa8\xd5\x62\xb7\xec\x1c\x85\x42\x38\x2d\x27\x10\xb0\x6c", + "CCS", + 18, + ), # eth / CacaoShares + ( + 1, + b"\x8a\x95\xca\x44\x8a\x52\xc0\xad\xf0\x05\x4b\xb3\x40\x2d\xc5\xe0\x9c\xd6\xb2\x32", + "CDL", + 18, + ), # eth / Confideal + ( + 1, + b"\x17\x7d\x39\xac\x67\x6e\xd1\xc6\x7a\x2b\x26\x8a\xd7\xf1\xe5\x88\x26\xe5\xb0\xaf", + "CDT", + 18, + ), # eth / CoinDash + ( + 1, + b"\x6f\xff\x38\x06\xbb\xac\x52\xa2\x0e\x0d\x79\xbc\x53\x8d\x52\x7f\x6a\x22\xc9\x6b", + "CDX", + 18, + ), # eth / CDX + ( + 1, + b"\x2c\xb1\x01\xd7\xda\x0e\xba\xa5\x7d\x3f\x2f\xef\x46\xd7\xff\xb7\xbb\x64\x59\x2b", + "CDX", + 0, + ), # eth / Carbon Dollar X + ( + 1, + b"\xb0\x56\xc3\x8f\x6b\x7d\xc4\x06\x43\x67\x40\x3e\x26\x42\x4c\xd2\xc6\x06\x55\xe1", + "CEEK", + 18, + ), # eth / CEEK VR Token + ( + 1, + b"\x12\xfe\xf5\xe5\x7b\xf4\x58\x73\xcd\x9b\x62\xe9\xdb\xd7\xbf\xb9\x9e\x32\xd7\x3e", + "CFI", + 18, + ), # eth / Cofound.it + ( + 1, + b"\x69\x56\x98\x3f\x8b\x3c\xe1\x73\xb4\xab\x84\x36\x1a\xa0\xad\x52\xf3\x8d\x93\x6f", + "CFTY", + 8, + ), # eth / Crafty Token + ( + 1, + b"\xba\x9d\x41\x99\xfa\xb4\xf2\x6e\xfe\x35\x51\xd4\x90\xe3\x82\x14\x86\xf1\x35\xba", + "CHSB", + 8, + ), # eth / CHSB + ( + 1, + b"\x06\x01\x2c\x8c\xf9\x7b\xea\xd5\xde\xae\x23\x70\x70\xf9\x58\x7f\x8e\x7a\x26\x6d", + "CK", + 0, + ), # eth / CK + ( + 1, + b"\xb1\xc1\xcb\x8c\x7c\x19\x92\xdb\xa2\x4e\x62\x8b\xf7\xd3\x8e\x71\xda\xd4\x6a\xeb", + "CLB", + 18, + ), # eth / Cloudbric + ( + 1, + b"\x3d\xc9\xa4\x2f\xa7\xaf\xe5\x7b\xe0\x3c\x58\xfd\x7f\x44\x11\xb1\xe4\x66\xc5\x08", + "CLL", + 18, + ), # eth / CryptoLiveLeak + ( + 1, + b"\x41\x62\x17\x8b\x78\xd6\x98\x54\x80\xa3\x08\xb2\x19\x0e\xe5\x51\x74\x60\x40\x6d", + "CLN", + 18, + ), # eth / ColuLocalNetwork + ( + 1, + b"\x7f\xce\x28\x56\x89\x9a\x68\x06\xee\xef\x70\x80\x79\x85\xfc\x75\x54\xc6\x63\x40", + "CLP", + 9, + ), # eth / CryptoLending + ( + 1, + b"\x3e\xdd\x23\x5c\x3e\x84\x0c\x1f\x29\x28\x6b\x2e\x39\x37\x0a\x25\x5c\x7b\x6f\xdb", + "CMBT", + 8, + ), # eth / CMBToken + ( + 1, + b"\x7e\x66\x75\x25\x52\x1c\xf6\x13\x52\xe2\xe0\x1b\x50\xfa\xaa\xe7\xdf\x39\x74\x9a", + "CMC", + 18, + ), # eth / CryptoMart + ( + 1, + b"\xf8\x5f\xee\xa2\xfd\xd8\x1d\x51\x17\x7f\x6b\x8f\x35\xf0\xe6\x73\x4c\xe4\x5f\x5f", + "CMT", + 18, + ), # eth / CyberMiles Token + ( + 1, + b"\xeb\xf2\xf9\xe8\xde\x96\x0f\x64\xec\x0f\xdc\xda\x6c\xb2\x82\x42\x31\x33\x34\x7b", + "CNB", + 8, + ), # eth / Canabio + ( + 1, + b"\xd4\xc4\x35\xf5\xb0\x9f\x85\x5c\x33\x17\xc8\x52\x4c\xb1\xf5\x86\xe4\x27\x95\xfa", + "CND", + 18, + ), # eth / Cindicator + ( + 1, + b"\xb4\xb1\xd2\xc2\x17\xec\x07\x76\x58\x4c\xe0\x8d\x3d\xd9\x8f\x90\xed\xed\xa4\x4b", + "CO2", + 18, + ), # eth / Climatecoin + ( + 1, + b"\x57\x4b\x36\xbc\xed\x44\x33\x38\x87\x5d\x17\x1c\xc3\x77\xe6\x91\xf7\xd4\xf8\x87", + "CO2Bit", + 18, + ), # eth / CO2Bit + ( + 1, + b"\xb2\xf7\xeb\x1f\x2c\x37\x64\x5b\xe6\x1d\x73\x95\x30\x35\x36\x0e\x76\x8d\x81\xe6", + "COB", + 18, + ), # eth / Cobinhood Token + ( + 1, + b"\x31\x36\xef\x85\x15\x92\xac\xf4\x9c\xa4\xc8\x25\x13\x1e\x36\x41\x70\xfa\x32\xb3", + "COFI", + 18, + ), # eth / CoinFi Token + ( + 1, + b"\x0c\x91\xb0\x15\xab\xa6\xf7\xb4\x73\x8d\xcd\x36\xe7\x41\x01\x38\xb2\x9a\xdc\x29", + "COIL", + 8, + ), # eth / CoinOil + ( + 1, + b"\x5e\x8f\x85\x59\x66\xd6\x38\x13\x5a\x96\x88\x61\xe8\x0d\xda\x72\x22\x91\xb0\x6d", + "COIN", + 18, + ), # eth / Coinvest V2 Token + ( + 1, + b"\x65\x29\x2e\xea\xdf\x14\x26\xcd\x2d\xf1\xc4\x79\x3a\x3d\x75\x19\xf2\x53\x91\x3b", + "COSS", + 18, + ), # eth / Coss Token + ( + 1, + b"\x9e\x96\x60\x44\x45\xec\x19\xff\xed\x9a\x5e\x8d\xd7\xb5\x0a\x29\xc8\x99\xa1\x0c", + "COSS", + 18, + ), # eth / Coss Token + ( + 1, + b"\xe2\xfb\x65\x29\xef\x56\x6a\x08\x0e\x6d\x23\xde\x0b\xd3\x51\x31\x10\x87\xd5\x67", + "COV", + 18, + ), # eth / Covesting + ( + 1, + b"\xb7\x87\xd4\xea\xc8\x89\x97\x30\xbb\x8c\x57\xfc\x3c\x99\x8c\x49\xc5\x24\x4e\xc0", + "CPEX", + 8, + ), # eth / CoinPulseToken + ( + 1, + b"\xf4\x47\x45\xfb\xd4\x1f\x6a\x1b\xa1\x51\xdf\x19\x0d\xb0\x56\x4c\x5f\xcc\x44\x10", + "CPY", + 18, + ), # eth / COPYTRACK + ( + 1, + b"\x7f\x58\x5b\x91\x30\xc6\x4e\x9e\x9f\x47\x0b\x61\x8a\x7b\xad\xd0\x3d\x79\xca\x7e", + "CR7", + 18, + ), # eth / CR7Coin + ( + 1, + b"\xae\xf3\x8f\xbf\xbf\x93\x2d\x1a\xef\x3b\x80\x8b\xc8\xfb\xd8\xcd\x8e\x1f\x8b\xc5", + "CRB", + 8, + ), # eth / CRB + ( + 1, + b"\x67\x2a\x1a\xd4\xf6\x67\xfb\x18\xa3\x33\xaf\x13\x66\x7a\xa0\xaf\x1f\x5b\x5b\xdd", + "CRED", + 18, + ), # eth / CRED + ( + 1, + b"\x4e\x06\x03\xe2\xa2\x7a\x30\x48\x0e\x5e\x3a\x4f\xe5\x48\xe2\x9e\xf1\x2f\x64\xbe", + "CREDO", + 18, + ), # eth / Credo / Bitbounce + ( + 1, + b"\x80\xa7\xe0\x48\xf3\x7a\x50\x50\x03\x51\xc2\x04\xcb\x40\x77\x66\xfa\x3b\xae\x7f", + "CRPT", + 18, + ), # eth / CrypteriumToken + ( + 1, + b"\xf0\xda\x11\x86\xa4\x97\x72\x26\xb9\x13\x5d\x06\x13\xee\x72\xe2\x29\xec\x3f\x4d", + "CRT", + 18, + ), # eth / CreamtoeCoin + ( + 1, + b"\xe4\xc9\x4d\x45\xf7\xae\xf7\x01\x8a\x5d\x66\xf4\x4a\xf7\x80\xec\x60\x23\x37\x8e", + "CryptoCarbon", + 6, + ), # eth / CryptoCarbon + ( + 1, + b"\x45\x45\x75\x0f\x39\xaf\x6b\xe4\xf2\x37\xb6\x86\x9d\x4e\xcc\xa9\x28\xfd\x5a\x85", + "CTF", + 18, + ), # eth / CryptoTask + ( + 1, + b"\xc8\x7c\x5d\xd8\x6a\x3d\x56\x7f\xf2\x87\x01\x88\x6f\xb0\x74\x5a\xaa\x89\x8d\xa4", + "CTG", + 18, + ), # eth / CT Global Token + ( + 1, + b"\xbf\x4c\xfd\x7d\x1e\xde\xee\xa5\xf6\x60\x08\x27\x41\x1b\x41\xa2\x1e\xb0\x8a\xbd", + "CTL", + 2, + ), # eth / CTL + ( + 1, + b"\xe3\xfa\x17\x7a\xce\xcf\xb8\x67\x21\xcf\x6f\x9f\x42\x06\xbd\x3b\xd6\x72\xd7\xd5", + "CTT", + 18, + ), # eth / ChainTrade Token + ( + 1, + b"\x66\x2a\xbc\xad\x0b\x7f\x34\x5a\xb7\xff\xb1\xb1\xfb\xb9\xdf\x78\x94\xf1\x8e\x66", + "CTX", + 18, + ), # eth / CarTaxi + ( + 1, + b"\xda\x6c\xb5\x8a\x0d\x0c\x01\x61\x0a\x29\xc5\xa6\x5c\x30\x3e\x13\xe8\x85\x88\x7c", + "cV", + 18, + ), # eth / carVertical + ( + 1, + b"\x41\xe5\x56\x00\x54\x82\x4e\xa6\xb0\x73\x2e\x65\x6e\x3a\xd6\x4e\x20\xe9\x4e\x45", + "CVC", + 8, + ), # eth / CVC + ( + 1, + b"\x21\x34\x05\x7c\x0b\x46\x1f\x89\x8d\x37\x5c\xea\xd6\x52\xac\xae\x62\xb5\x95\x41", + "CXC", + 18, + ), # eth / CoxxxCoin + ( + 1, + b"\xb6\xee\x96\x68\x77\x1a\x79\xbe\x79\x67\xee\x29\xa6\x3d\x41\x84\xf8\x09\x71\x43", + "CXO", + 18, + ), # eth / CargoX + ( + 1, + b"\xda\xb0\xc3\x1b\xf3\x4c\x89\x7f\xb0\xfe\x90\xd1\x2e\xc9\x40\x1c\xaf\x5c\x36\xec", + "DAB", + 0, + ), # eth / DAB + ( + 1, + b"\xfb\x2f\x26\xf2\x66\xfb\x28\x05\xa3\x87\x23\x0f\x2a\xa0\xa3\x31\xb4\xd9\x6f\xba", + "DADI", + 18, + ), # eth / DADI + ( + 1, + b"\x89\xd2\x4a\x6b\x4c\xcb\x1b\x6f\xaa\x26\x25\xfe\x56\x2b\xdd\x9a\x23\x26\x03\x59", + "DAI", + 18, + ), # eth / Dai Stablecoin v1.0 + ( + 1, + b"\x07\xd9\xe4\x9e\xa4\x02\x19\x4b\xf4\x8a\x82\x76\xda\xfb\x16\xe4\xed\x63\x33\x17", + "DALC", + 8, + ), # eth / DaleCoin + ( + 1, + b"\x9b\x70\x74\x0e\x70\x8a\x08\x3c\x6f\xf3\x8d\xf5\x22\x97\x02\x0f\x5d\xfa\xa5\xee", + "DAN", + 10, + ), # eth / DaneelToken + ( + 1, + b"\xbb\x9b\xc2\x44\xd7\x98\x12\x3f\xde\x78\x3f\xcc\x1c\x72\xd3\xbb\x8c\x18\x94\x13", + "DAO", + 16, + ), # eth / DAO + ( + 1, + b"\x81\xc9\x15\x1d\xe0\xc8\xba\xfc\xd3\x25\xa5\x7e\x3d\xb5\xa5\xdf\x1c\xeb\xf7\x9c", + "DAT", + 18, + ), # eth / Datum Token + ( + 1, + b"\x1b\x5f\x21\xee\x98\xee\xd4\x8d\x29\x2e\x8e\x2d\x3e\xd8\x2b\x40\xa9\x72\x8a\x22", + "DATABroker", + 18, + ), # eth / DataBrokerDAO Token + ( + 1, + b"\x0c\xf0\xee\x63\x78\x8a\x08\x49\xfe\x52\x97\xf3\x40\x7f\x70\x1e\x12\x2c\xc0\x23", + "DATACoin", + 18, + ), # eth / DATACoin + ( + 1, + b"\xd8\x2d\xf0\xab\xd3\xf5\x14\x25\xeb\x15\xef\x75\x80\xfd\xa5\x57\x27\x87\x5f\x14", + "DAV", + 18, + ), # eth / DAV Token + ( + 1, + b"\x61\x72\x5f\x3d\xb4\x00\x4a\xfe\x01\x47\x45\xb2\x1d\xab\x1e\x16\x77\xcc\x32\x8b", + "DAXT", + 18, + ), # eth / Digital Asset Exchange Token + ( + 1, + b"\xe8\x14\xae\xe9\x60\xa8\x52\x08\xc3\xdb\x54\x2c\x53\xe7\xd4\xa6\xc8\xd5\xf6\x0f", + "DAY", + 18, + ), # eth / ChronoLogic DAY + ( + 1, + b"\x38\x6f\xaa\x47\x03\xa3\x4a\x7f\xdb\x19\xbe\xc2\xe1\x4f\xd4\x27\xc9\x63\x84\x16", + "DCA", + 18, + ), # eth / DoBetAcceptBet + ( + 1, + b"\x39\x9a\x0e\x6f\xbe\xb3\xd7\x4c\x85\x35\x74\x39\xf4\xc8\xae\xd9\x67\x8a\x5c\xbf", + "DCL", + 3, + ), # eth / DCL + ( + 1, + b"\x08\xd3\x2b\x0d\xa6\x3e\x2c\x3b\xcf\x80\x19\xc9\xc5\xd8\x49\xd7\xa9\xd7\x91\xe6", + "DCN", + 0, + ), # eth / Dentacoin + ( + 1, + b"\xcc\x4e\xf9\xee\xaf\x65\x6a\xc1\xa2\xab\x88\x67\x43\xe9\x8e\x97\xe0\x90\xed\x38", + "DDF", + 18, + ), # eth / DDF + ( + 1, + b"\x15\x12\x02\xc9\xc1\x8e\x49\x56\x56\xf3\x72\x28\x1f\x49\x3e\xb7\x69\x89\x61\xd5", + "DEB", + 18, + ), # eth / DEBITUM + ( + 1, + b"\x07\x5c\x60\xee\x2c\xd3\x08\xff\x47\x87\x3b\x38\xbd\x9a\x0f\xa5\x85\x33\x82\xc4", + "DEEZ", + 18, + ), # eth / DeezNuts + ( + 1, + b"\x35\x97\xbf\xd5\x33\xa9\x9c\x9a\xa0\x83\x58\x7b\x07\x44\x34\xe6\x1e\xb0\xa2\x58", + "DENT", + 8, + ), # eth / DENT + ( + 1, + b"\x7c\xf2\x71\x96\x6f\x36\x34\x3b\xf0\x15\x0f\x25\xe5\x36\x4f\x79\x61\xc5\x82\x01", + "DEPO", + 0, + ), # eth / CRYPTODEPOZIT + ( + 1, + b"\xdd\x94\xde\x9c\xfe\x06\x35\x77\x05\x1a\x5e\xb7\x46\x5d\x08\x31\x7d\x88\x08\xb6", + "Devcon2 Token", + 0, + ), # eth / Devcon2 Token + ( + 1, + b"\xe0\xb7\x92\x7c\x4a\xf2\x37\x65\xcb\x51\x31\x4a\x0e\x05\x21\xa9\x64\x5f\x0e\x2a", + "DGD", + 9, + ), # eth / Digix DAO + ( + 1, + b"\xf6\xcf\xe5\x3d\x6f\xeb\xae\xea\x05\x1f\x40\x0f\xf5\xfc\x14\xf0\xcb\xbd\xac\xa1", + "DGPT", + 18, + ), # eth / DigiPulse + ( + 1, + b"\x55\xb9\xa1\x1c\x2e\x83\x51\xb4\xff\xc7\xb1\x15\x61\x14\x8b\xfa\xc9\x97\x78\x55", + "DGX", + 9, + ), # eth / DGX + ( + 1, + b"\x2e\x07\x1d\x29\x66\xaa\x7d\x8d\xec\xb1\x00\x58\x85\xba\x19\x77\xd6\x03\x8a\x65", + "DICE", + 16, + ), # eth / Etheroll + ( + 1, + b"\x13\xf1\x1c\x99\x05\xa0\x8c\xa7\x6e\x3e\x85\x3b\xe6\x3d\x4f\x09\x44\x32\x6c\x72", + "DIVX", + 18, + ), # eth / DIVX + ( + 1, + b"\xba\x18\x7b\x09\xff\xa8\xdd\xdc\x80\xd2\x57\x1e\xd3\xcb\xc4\xbe\x0a\xf6\x9e\x0c", + "DKP", + 18, + ), # eth / Draggin Karma Points + ( + 1, + b"\x07\xe3\xc7\x06\x53\x54\x8b\x04\xf0\xa7\x59\x70\xc1\xf8\x1b\x4c\xbb\xfb\x60\x6f", + "DLT", + 18, + ), # eth / Agrello + ( + 1, + b"\x2c\xcb\xff\x3a\x04\x2c\x68\x71\x6e\xd2\xa2\xcb\x0c\x54\x4a\x9f\x1d\x19\x35\xe1", + "DMT", + 8, + ), # eth / DMarket Token + ( + 1, + b"\x0a\xbd\xac\xe7\x0d\x37\x90\x23\x5a\xf4\x48\xc8\x85\x47\x60\x3b\x94\x56\x04\xea", + "DNT", + 18, + ), # eth / DistrictOx + ( + 1, + b"\xe4\x3e\x20\x41\xdc\x37\x86\xe1\x66\x96\x1e\xd9\x48\x4a\x55\x39\x03\x3d\x10\xfb", + "DNX", + 18, + ), # eth / DenCity + ( + 1, + b"\x76\x97\x4c\x7b\x79\xdc\x8a\x6a\x10\x9f\xd7\x1f\xd7\xce\xb9\xe4\x0e\xff\x53\x82", + "DOW", + 18, + ), # eth / DOW + ( + 1, + b"\xee\xf6\xe9\x00\x34\xee\xa8\x9e\x31\xeb\x4b\x8e\xac\xd3\x23\xf2\x8a\x92\xea\xe4", + "DOW", + 18, + ), # eth / DOW + ( + 1, + b"\x01\xb3\xec\x4a\xae\x1b\x87\x29\x52\x9b\xeb\x49\x65\xf2\x7d\x00\x87\x88\xb0\xeb", + "DPP", + 18, + ), # eth / Digital Assets Power Play + ( + 1, + b"\x41\x9c\x4d\xb4\xb9\xe2\x5d\x6d\xb2\xad\x96\x91\xcc\xb8\x32\xc8\xd9\xfd\xa0\x5e", + "DRGN", + 18, + ), # eth / Dragon + ( + 1, + b"\x3c\x75\x22\x65\x55\xfc\x49\x61\x68\xd4\x8b\x88\xdf\x83\xb9\x5f\x16\x77\x1f\x37", + "DROP", + 0, + ), # eth / Droplex + ( + 1, + b"\x46\x72\xba\xd5\x27\x10\x74\x71\xcb\x50\x67\xa8\x87\xf4\x65\x6d\x58\x5a\x8a\x31", + "DROP (dropil)", + 18, + ), # eth / Dropil + ( + 1, + b"\x27\x99\xd9\x0c\x6d\x44\xcb\x9a\xa5\xfb\xc3\x77\x17\x7f\x16\xc3\x3e\x05\x6b\x82", + "DRP", + 0, + ), # eth / Dripcoin + ( + 1, + b"\x62\x1d\x78\xf2\xef\x2f\xd9\x37\xbf\xca\x69\x6c\xab\xaf\x9a\x77\x9f\x59\xb3\xed", + "DRP", + 2, + ), # eth / DCorp + ( + 1, + b"\x1e\x09\xbd\x8c\xad\xb4\x41\x63\x2e\x44\x1d\xb3\xe1\xd7\x99\x09\xee\x0a\x22\x56", + "DSC", + 1, + ), # eth / Digital Safe Coin + ( + 1, + b"\x5a\xdc\x96\x1d\x6a\xc3\xf7\x06\x2d\x2e\xa4\x5f\xef\xb8\xd8\x16\x7d\x44\xb1\x90", + "DTH", + 18, + ), # eth / dether + ( + 1, + b"\xd2\x34\xbf\x24\x10\xa0\x00\x9d\xf9\xc3\xc6\x3b\x61\x0c\x09\x73\x8f\x18\xcc\xd7", + "DTR", + 8, + ), # eth / DTR + ( + 1, + b"\xf9\xf7\xc2\x9c\xfd\xf1\x9f\xcf\x1f\x2a\xa6\xb8\x4a\xa3\x67\xbc\xf1\xbd\x16\x76", + "DTT", + 18, + ), # eth / Delphi Tech Token + ( + 1, + b"\x76\x5f\x0c\x16\xd1\xdd\xc2\x79\x29\x5c\x1a\x7c\x24\xb0\x88\x3f\x62\xd3\x3f\x75", + "DTX", + 18, + ), # eth / DaTa eXchange Token + ( + 1, + b"\x82\xfd\xed\xfb\x76\x35\x44\x1a\xa5\xa9\x27\x91\xd0\x01\xfa\x73\x88\xda\x80\x25", + "DTx", + 18, + ), # eth / DigitalTicks + ( + 1, + b"\x9c\x6f\xa4\x22\x09\x16\x9b\xce\xa0\x32\xe4\x01\x18\x8a\x6f\xc3\xe9\xc9\xf5\x9c", + "DUBI", + 18, + ), # eth / Decentralized Universal Basic Income + ( + 1, + b"\xd4\xcf\xfe\xef\x10\xf6\x0e\xca\x58\x1b\x5e\x11\x46\xb5\xac\xa4\x19\x4a\x4c\x3b", + "DUBI", + 18, + ), # eth / Decentralized Universal Basic Income + ( + 1, + b"\x99\x4f\x0d\xff\xdb\xae\x0b\xbf\x09\xb6\x52\xd6\xf1\x1a\x49\x3f\xd3\x3f\x42\xb9", + "EAGLE", + 18, + ), # eth / EagleCoin + ( + 1, + b"\xaf\xc3\x97\x88\xc5\x1f\x0c\x1f\xf7\xb5\x53\x17\xf3\xe7\x02\x99\xe5\x21\xff\xf6", + "eBCH", + 8, + ), # eth / eBCH + ( + 1, + b"\xeb\x7c\x20\x02\x71\x72\xe5\xd1\x43\xfb\x03\x0d\x50\xf9\x1c\xec\xe2\xd1\x48\x5d", + "eBTC", + 8, + ), # eth / eBTC + ( + 1, + b"\xa5\x78\xac\xc0\xcb\x78\x75\x78\x1b\x78\x80\x90\x3f\x45\x94\xd1\x3c\xfa\x8b\x98", + "ECN", + 2, + ), # eth / ECN + ( + 1, + b"\x17\xf9\x34\x75\xd2\xa9\x78\xf5\x27\xc3\xf7\xc4\x4a\xbf\x44\xad\xfb\xa6\x0d\x5c", + "ECO2", + 2, + ), # eth / EtherCO2 + ( + 1, + b"\xfa\x1d\xe2\xee\x97\xe4\xc1\x0c\x94\xc9\x1c\xb2\xb5\x06\x2b\x89\xfb\x14\x0b\x82", + "EDC", + 6, + ), # eth / Education Credits + ( + 1, + b"\x08\x71\x1d\x3b\x02\xc8\x75\x8f\x2f\xb3\xab\x4e\x80\x22\x84\x18\xa7\xf8\xe3\x9c", + "EDG", + 0, + ), # eth / Edgeless + ( + 1, + b"\xce\xd4\xe9\x31\x98\x73\x4d\xda\xff\x84\x92\xd5\x25\xbd\x25\x8d\x49\xeb\x38\x8e", + "EDO", + 18, + ), # eth / Eidoo + ( + 1, + b"\x5b\x26\xc5\xd0\x77\x2e\x5b\xba\xc8\xb3\x18\x2a\xe9\xa1\x3f\x9b\xb2\xd0\x37\x65", + "EDU", + 8, + ), # eth / EDU + ( + 1, + b"\x2a\x22\xe5\xcc\xa0\x0a\x3d\x63\x30\x8f\xa3\x9f\x29\x20\x2e\xb1\xb3\x9e\xef\x52", + "EDU", + 6, + ), # eth / EDU Token + ( + 1, + b"\xb5\x3a\x96\xbc\xbd\xd9\xcf\x78\xdf\xf2\x0b\xab\x6c\x2b\xe7\xba\xec\x8f\x00\xf8", + "eGAS", + 8, + ), # eth / ETH GAS + ( + 1, + b"\x8e\x1b\x44\x8e\xc7\xad\xfc\x7f\xa3\x5f\xc2\xe8\x85\x67\x8b\xd3\x23\x17\x6e\x34", + "EGT", + 18, + ), # eth / Egretia Token + ( + 1, + b"\xf9\xf0\xfc\x71\x67\xc3\x11\xdd\x2f\x1e\x21\xe9\x20\x4f\x87\xeb\xa9\x01\x2f\xb2", + "EHT", + 8, + ), # eth / EasyHomes + ( + 1, + b"\xbf\x21\x79\x85\x9f\xc6\xd5\xbe\xe9\xbf\x91\x58\x63\x2d\xc5\x16\x78\xa4\x10\x0e", + "ELF", + 18, + ), # eth / ELF Token + ( + 1, + b"\xc8\xc6\xa3\x1a\x4a\x80\x6d\x37\x10\xa7\xb3\x8b\x7b\x29\x6d\x2f\xab\xcc\xdb\xa8", + "ELIX", + 18, + ), # eth / Elixir Token + ( + 1, + b"\x44\x19\x7a\x4c\x44\xd6\xa0\x59\x29\x7c\xaf\x6b\xe4\xf7\xe1\x72\xbd\x56\xca\xaf", + "ELTCOIN", + 8, + ), # eth / ELTCOIN + ( + 1, + b"\xb6\x7b\x88\xa2\x57\x08\xa3\x5a\xe7\xc2\xd7\x36\xd3\x98\xd2\x68\xce\x4f\x7f\x83", + "EMON", + 8, + ), # eth / Etheremon + ( + 1, + b"\x95\xda\xaa\xb9\x80\x46\x84\x6b\xf4\xb2\x85\x3e\x23\xcb\xa2\x36\xfa\x39\x4a\x31", + "EMONT", + 8, + ), # eth / Etheremon Token + ( + 1, + b"\x95\x01\xbf\xc4\x88\x97\xdc\xee\xad\xf7\x31\x13\xef\x63\x5d\x2f\xf7\xee\x4b\x97", + "EMT", + 18, + ), # eth / easyMINE Token + ( + 1, + b"\xb8\x02\xb2\x4e\x06\x37\xc2\xb8\x7d\x2e\x8b\x77\x84\xc0\x55\xbb\xe9\x21\x01\x1a", + "EMV", + 2, + ), # eth / EMovieVenture + ( + 1, + b"\x03\x9f\x50\x50\xde\x49\x08\xf9\xb5\xdd\xf4\x0a\x4f\x3a\xa3\xf3\x29\x08\x63\x87", + "ENC", + 18, + ), # eth / Ethernet.Cash + ( + 1, + b"\xf0\xee\x6b\x27\xb7\x59\xc9\x89\x3c\xe4\xf0\x94\xb4\x9a\xd2\x8f\xd1\x5a\x23\xe4", + "ENG", + 8, + ), # eth / Enigma + ( + 1, + b"\xf6\x29\xcb\xd9\x4d\x37\x91\xc9\x25\x01\x52\xbd\x8d\xfb\xdf\x38\x0e\x2a\x3b\x9c", + "ENJ", + 18, + ), # eth / ENJIN + ( + 1, + b"\x5b\xc7\xe5\xf0\xab\x8b\x2e\x10\xd2\xd0\xa3\xf2\x17\x39\xfc\xe6\x24\x59\xae\xf3", + "ENTRP", + 18, + ), # eth / Hut34 Entropy Token + ( + 1, + b"\x86\xfa\x04\x98\x57\xe0\x20\x9a\xa7\xd9\xe6\x16\xf7\xeb\x3b\x3b\x78\xec\xfd\xb0", + "EOS", + 18, + ), # eth / EOS + ( + 1, + b"\x7e\x9e\x43\x1a\x0b\x8c\x4d\x53\x2c\x74\x5b\x10\x43\xc7\xfa\x29\xa4\x8d\x4f\xba", + "eosDAC", + 18, + ), # eth / eosDAC + ( + 1, + b"\x35\xba\xa7\x20\x38\xf1\x27\xf9\xf8\xc8\xf9\xb4\x91\x04\x9f\x64\xf3\x77\x91\x4d", + "EPX", + 4, + ), # eth / ethPoker.io EPX + ( + 1, + b"\xe8\xa1\xdf\x95\x8b\xe3\x79\x04\x5e\x2b\x46\xa3\x1a\x98\xb9\x3a\x2e\xcd\xfd\xed", + "ESZ", + 18, + ), # eth / ESZCoin + ( + 1, + b"\x1b\x97\x43\xf5\x56\xd6\x5e\x75\x7c\x4c\x65\x0b\x45\x55\xba\xf3\x54\xcb\x8b\xd3", + "ETBS", + 12, + ), # eth / Ethbits + ( + 1, + b"\xdd\x74\xa7\xa3\x76\x9f\xa7\x25\x61\xb3\xa6\x9e\x65\x96\x8f\x49\x74\x8c\x69\x0c", + "ETCH", + 18, + ), # eth / ETCH + ( + 1, + b"\x3a\x26\x74\x6d\xdb\x79\xb1\xb8\xe4\x45\x0e\x3f\x4f\xfe\x32\x85\xa3\x07\x38\x7e", + "ETHB", + 8, + ), # eth / EtherBTC + ( + 1, + b"\x69\x27\xc6\x9f\xb4\xda\xf2\x04\x3f\xbb\x1c\xb7\xb8\x6c\x56\x61\x41\x6b\xea\x29", + "ETR", + 18, + ), # eth / Etheruem Risen + ( + 1, + b"\xab\xdf\x14\x78\x70\x23\x5f\xcf\xc3\x41\x53\x82\x8c\x76\x9a\x70\xb3\xfa\xe0\x1f", + "EURT", + 6, + ), # eth / EUR Tether (erc20) + ( + 1, + b"\x52\x36\x30\x97\x6e\xb6\x14\x76\x21\xb5\xc3\x1c\x78\x1e\xbe\x2e\xc2\xa8\x06\xe0", + "eUSD", + 18, + ), # eth / Ether-Backed USD Nomins (erc20) + ( + 1, + b"\x92\x31\x08\xa4\x39\xc4\xe8\xc2\x31\x5c\x4f\x65\x21\xe5\xce\x95\xb4\x4e\x9b\x4c", + "EVE", + 18, + ), # eth / EVE + ( + 1, + b"\xd7\x80\xae\x2b\xf0\x4c\xd9\x6e\x57\x7d\x3d\x01\x47\x62\xf8\x31\xd9\x71\x29\xd0", + "EVN", + 18, + ), # eth / Envion AG + ( + 1, + b"\xf3\xdb\x5f\xa2\xc6\x6b\x7a\xf3\xeb\x0c\x0b\x78\x25\x10\x81\x6c\xbe\x48\x13\xb8", + "EVX", + 4, + ), # eth / EVX Token + ( + 1, + b"\xc9\x8e\x06\x39\xc6\xd2\xec\x03\x7a\x61\x53\x41\xc3\x69\x66\x6b\x11\x0e\x80\xe5", + "EXMR", + 8, + ), # eth / eXMRcoin + ( + 1, + b"\x19\x0e\x56\x9b\xe0\x71\xf4\x0c\x70\x4e\x15\x82\x5f\x28\x54\x81\xcb\x74\xb6\xcc", + "FAM", + 12, + ), # eth / FAM + ( + 1, + b"\x7f\x67\x15\xc3\xfc\x47\x40\xa0\x2f\x70\xde\x85\xb9\xfd\x50\xac\x60\x01\xfe\xd9", + "FANX", + 18, + ), # eth / FANX Token + ( + 1, + b"\x00\x9e\x86\x49\x23\xb4\x92\x63\xc7\xf1\x0d\x19\xb7\xf8\xab\x7a\x9a\x5a\xad\x33", + "FKX", + 18, + ), # eth / Knoxstertoken + ( + 1, + b"\xf0\x4a\x8a\xc5\x53\xfc\xed\xb5\xba\x99\xa6\x47\x99\x15\x58\x26\xc1\x36\xb0\xbe", + "FLIXX", + 18, + ), # eth / FLIXX + ( + 1, + b"\x04\xcc\x78\x3b\x45\x0b\x8d\x11\xf3\xc7\xd0\x0d\xd0\x3f\xdf\x7f\xb5\x1f\xe9\xf2", + "FLMC", + 18, + ), # eth / Filmscoin + ( + 1, + b"\x59\x76\xf7\xda\xc1\x52\x5e\xf3\x27\x78\x36\x04\x3b\xa4\x74\xa3\x5e\x6b\x42\x72", + "FLMC", + 0, + ), # eth / Filmscoin + ( + 1, + b"\x3a\x1b\xda\x28\xad\xb5\xb0\xa8\x12\xa7\xcf\x10\xa1\x95\x0c\x92\x0f\x79\xbc\xd3", + "FLP", + 18, + ), # eth / FLIP Token + ( + 1, + b"\x9a\xef\xbe\x0b\x3c\x3b\xa9\xea\xb2\x62\xcb\x98\x56\xe8\x15\x7a\xb7\x64\x8e\x09", + "FLR", + 18, + ), # eth / Flair Coin + ( + 1, + b"\x95\x4b\x5d\xe0\x9a\x55\xe5\x97\x55\xac\xbd\xa2\x9e\x1e\xb7\x4a\x45\xd3\x01\x75", + "FLUZ", + 18, + ), # eth / Fluz Fluz Global + ( + 1, + b"\x70\xb1\x47\xe0\x1e\x92\x85\xe7\xce\x68\xb9\xba\x43\x7f\xe3\xa9\x19\x0e\x75\x6a", + "FLX", + 18, + ), # eth / BitFlux + ( + 1, + b"\x4d\xf4\x7b\x49\x69\xb2\x91\x1c\x96\x65\x06\xe3\x59\x2c\x41\x38\x94\x93\x95\x3b", + "FND", + 18, + ), # eth / FundRequest + ( + 1, + b"\x0a\xbe\xfb\x76\x11\xcb\x3a\x01\xea\x3f\xad\x85\xf3\x3c\x3c\x93\x4f\x8e\x2c\xf4", + "FRD", + 18, + ), # eth / FARAD Cryptoken + ( + 1, + b"\xe6\xf7\x4d\xcf\xa0\xe2\x08\x83\x00\x8d\x8c\x16\xb6\xd9\xa3\x29\x18\x9d\x0c\x30", + "FTC", + 2, + ), # eth / FTC + ( + 1, + b"\x20\x23\xdc\xf7\xc4\x38\xc8\xc8\xc0\xb0\xf2\x8d\xba\xe1\x55\x20\xb4\xf3\xee\x20", + "FTR", + 18, + ), # eth / Futourist Token + ( + 1, + b"\x2a\xec\x18\xc5\x50\x0f\x21\x35\x9c\xe1\xbe\xa5\xdc\x17\x77\x34\x4d\xf4\xc0\xdc", + "FTT", + 18, + ), # eth / FarmaTrust Token + ( + 1, + b"\x65\xbe\x44\xc7\x47\x98\x8f\xbf\x60\x62\x07\x69\x8c\x94\x4d\xf4\x44\x2e\xfe\x19", + "FUCK", + 4, + ), # eth / Finally Usable Crypto Karma + ( + 1, + b"\xab\x16\xe0\xd2\x5c\x06\xcb\x37\x62\x59\xcc\x18\xc1\xde\x4a\xca\x57\x60\x55\x89", + "FUCK", + 4, + ), # eth / FinallyUsableCryptoKarma + ( + 1, + b"\xea\x38\xea\xa3\xc8\x6c\x8f\x9b\x75\x15\x33\xba\x2e\x56\x2d\xeb\x9a\xcd\xed\x40", + "FUEL", + 18, + ), # eth / Etherparty FUEL + ( + 1, + b"\x41\x9d\x0d\x8b\xdd\x9a\xf5\xe6\x06\xae\x22\x32\xed\x28\x5a\xff\x19\x0e\x71\x1b", + "FUN", + 8, + ), # eth / Funfair + ( + 1, + b"\x88\xfc\xfb\xc2\x2c\x6d\x3d\xba\xa2\x5a\xf4\x78\xc5\x78\x97\x83\x39\xbd\xe7\x7a", + "FYN", + 18, + ), # eth / Fund Yourself Now + ( + 1, + b"\xf6\x74\x51\xdc\x84\x21\xf0\xe0\xaf\xeb\x52\xfa\xa8\x10\x10\x34\xed\x08\x1e\xd9", + "GAM", + 8, + ), # eth / Gambit + ( + 1, + b"\x67\x54\xe2\x1b\x9e\xaa\x05\x3c\x62\xd7\x85\x4d\xd6\x56\x1a\xe4\x51\xb0\xcb\xcf", + "GANA", + 18, + ), # eth / GANA + ( + 1, + b"\xc0\xea\x63\x06\xf6\x36\x0f\xe7\xdc\xab\x65\xd1\x6b\xf1\xa3\xaf\x92\xc7\x9a\xa2", + "GANA", + 18, + ), # eth / GANA + ( + 1, + b"\x70\x88\x76\xf4\x86\xe4\x48\xee\x89\xeb\x33\x2b\xfb\xc8\xe5\x93\x55\x30\x58\xb9", + "GAVEL", + 18, + ), # eth / GAVEL + ( + 1, + b"\x75\x85\xf8\x35\xae\x2d\x52\x27\x22\xd2\x68\x43\x23\xa0\xba\x83\x40\x1f\x32\xf5", + "GBT", + 18, + ), # eth / GBT + ( + 1, + b"\x12\xfc\xd6\x46\x3e\x66\x97\x4c\xf7\xbb\xc2\x4f\xfc\x4d\x40\xd6\xbe\x45\x82\x83", + "GBX", + 18, + ), # eth / Globitex + ( + 1, + b"\xdb\x0f\x69\x30\x6f\xf8\xf9\x49\xf2\x58\xe8\x3f\x6b\x87\xee\x5d\x05\x2d\x0b\x23", + "GCP", + 18, + ), # eth / Globcoin Crypto Platform + ( + 1, + b"\x4f\x4f\x0d\xb4\xde\x90\x3b\x88\xf2\xb1\xa2\x84\x79\x71\xe2\x31\xd5\x4f\x8f\xd3", + "GEE", + 8, + ), # eth / Geens NPO + ( + 1, + b"\x24\x08\x3b\xb3\x00\x72\x64\x3c\x3b\xb9\x0b\x44\xb7\x28\x58\x60\xa7\x55\xe6\x87", + "GELD", + 18, + ), # eth / GELD + ( + 1, + b"\x54\x3f\xf2\x27\xf6\x4a\xa1\x7e\xa1\x32\xbf\x98\x86\xca\xb5\xdb\x55\xdc\xad\xdf", + "GEN", + 18, + ), # eth / DAOstack + ( + 1, + b"\x8a\x85\x42\x88\xa5\x97\x60\x36\xa7\x25\x87\x91\x64\xca\x3e\x91\xd3\x0c\x6a\x1b", + "GET", + 18, + ), # eth / GET + ( + 1, + b"\xfc\xd8\x62\x98\x56\x28\xb2\x54\x06\x1f\x7a\x91\x80\x35\xb8\x03\x40\xd0\x45\xd3", + "GIF", + 18, + ), # eth / GIFcoin Token + ( + 1, + b"\xae\x4f\x56\xf0\x72\xc3\x4c\x0a\x65\xb3\xae\x3e\x4d\xb7\x97\xd8\x31\x43\x9d\x93", + "GIM", + 8, + ), # eth / Gimli + ( + 1, + b"\xb3\xbd\x49\xe2\x8f\x8f\x83\x2b\x8d\x1e\x24\x61\x06\x99\x1e\x54\x6c\x32\x35\x02", + "GMT", + 18, + ), # eth / GMT + ( + 1, + b"\x68\x10\xe7\x76\x88\x0c\x02\x93\x3d\x47\xdb\x1b\x9f\xc0\x59\x08\xe5\x38\x6b\x96", + "GNO", + 18, + ), # eth / Gnosis + ( + 1, + b"\xa7\x44\x76\x44\x31\x19\xa9\x42\xde\x49\x85\x90\xfe\x1f\x24\x54\xd7\xd4\xac\x0d", + "GNT", + 18, + ), # eth / Golem + ( + 1, + b"\xea\xb4\x31\x93\xcf\x06\x23\x07\x3c\xa8\x9d\xb9\xb7\x12\x79\x63\x56\xfa\x74\x14", + "GOLDX", + 18, + ), # eth / GOLDX + ( + 1, + b"\x12\xb1\x9d\x3e\x2c\xcc\x14\xda\x04\xfa\xe3\x3e\x63\x65\x2c\xe4\x69\xb3\xf2\xfd", + "GRID", + 12, + ), # eth / GRID + ( + 1, + b"\x0a\x9a\x9c\xe6\x00\xd0\x8b\xf9\xb7\x6f\x49\xfa\x4e\x7b\x38\xa6\x7e\xbe\xb1\xe6", + "GROW", + 8, + ), # eth / Growchain + ( + 1, + b"\xb7\x08\x35\xd7\x82\x2e\xbb\x94\x26\xb5\x65\x43\xe3\x91\x84\x6c\x10\x7b\xd3\x2c", + "GTC", + 18, + ), # eth / GTC Token + ( + 1, + b"\x02\x5a\xba\xd9\xe5\x18\x51\x6f\xda\xaf\xbd\xcd\xb9\x70\x1b\x37\xfb\x7e\xf0\xfa", + "GTKT", + 0, + ), # eth / GTKT + ( + 1, + b"\xc5\xbb\xae\x50\x78\x1b\xe1\x66\x93\x06\xb9\xe0\x01\xef\xf5\x7a\x29\x57\xb0\x9d", + "GTO", + 5, + ), # eth / Gifto + ( + 1, + b"\xf7\xb0\x98\x29\x8f\x7c\x69\xfc\x14\x61\x0b\xf7\x1d\x5e\x02\xc6\x07\x92\x89\x4c", + "GUP", + 3, + ), # eth / GUP + ( + 1, + b"\x10\x3c\x3a\x20\x9d\xa5\x9d\x3e\x7c\x4a\x89\x30\x7e\x66\x52\x1e\x08\x1c\xfd\xf0", + "GVT", + 18, + ), # eth / Genesis Vision + ( + 1, + b"\x58\xca\x30\x65\xc0\xf2\x4c\x7c\x96\xae\xe8\xd6\x05\x6b\x5b\x5d\xec\xf9\xc2\xf8", + "GXC", + 10, + ), # eth / GXC + ( + 1, + b"\x22\xf0\xaf\x8d\x78\x85\x1b\x72\xee\x79\x9e\x05\xf5\x4a\x77\x00\x15\x86\xb1\x8a", + "GXVC", + 10, + ), # eth / Genevieve VC + ( + 1, + b"\x8c\x65\xe9\x92\x29\x7d\x5f\x09\x2a\x75\x6d\xef\x24\xf4\x78\x1a\x28\x01\x98\xff", + "GZE", + 18, + ), # eth / GazeCoin + ( + 1, + b"\xe6\x38\xdc\x39\xb6\xad\xbe\xe8\x52\x6b\x5c\x22\x38\x0b\x4b\x45\xda\xf4\x6d\x8e", + "GZR", + 6, + ), # eth / Gizer + ( + 1, + b"\x90\x02\xd4\x48\x5b\x75\x94\xe3\xe8\x50\xf0\xa2\x06\x71\x3b\x30\x51\x13\xf6\x9e", + "HAT", + 18, + ), # eth / Hawala Today + ( + 1, + b"\xc0\x11\xa7\x24\x00\xe5\x8e\xcd\x99\xee\x49\x7c\xf8\x9e\x37\x75\xd4\xbd\x73\x2f", + "HAV", + 18, + ), # eth / Havven + ( + 1, + b"\xff\xe8\x19\x6b\xc2\x59\xe8\xde\xdc\x54\x4d\x93\x57\x86\xaa\x47\x09\xec\x3e\x64", + "HDG", + 18, + ), # eth / Hedge Crypto + ( + 1, + b"\xe9\xff\x07\x80\x9c\xcf\xf0\x5d\xae\x74\x99\x0e\x25\x83\x1d\x0b\xc5\xcb\xe5\x75", + "Hdp", + 18, + ), # eth / HEdpAY + ( + 1, + b"\xba\x21\x84\x52\x0a\x1c\xc4\x9a\x61\x59\xc5\x7e\x61\xe1\x84\x4e\x08\x56\x15\xb6", + "HGT", + 8, + ), # eth / HGT + ( + 1, + b"\xa9\x24\x0f\xbc\xac\x1f\x0b\x9a\x6a\xdf\xb0\x4a\x53\xc8\xe3\xb0\xcc\x1d\x14\x44", + "HIG", + 18, + ), # eth / ethereumhigh + ( + 1, + b"\x14\xf3\x7b\x57\x42\x42\xd3\x66\x55\x8d\xb6\x1f\x33\x35\x28\x9a\x50\x35\xc5\x06", + "HKG", + 3, + ), # eth / HKG + ( + 1, + b"\x88\xac\x94\xd5\xd1\x75\x13\x03\x47\xfc\x95\xe1\x09\xd7\x7a\xc0\x9d\xbf\x5a\xb7", + "HKY", + 18, + ), # eth / Hicky + ( + 1, + b"\xcb\xcc\x0f\x03\x6e\xd4\x78\x8f\x63\xfc\x0f\xee\x32\x87\x3d\x6a\x74\x87\xb9\x08", + "HMQ", + 8, + ), # eth / HMQ + ( + 1, + b"\xb4\x5d\x7b\xc4\xce\xbc\xab\x98\xad\x09\xba\xbd\xf8\xc8\x18\xb2\x29\x2b\x67\x2c", + "HODL", + 18, + ), # eth / HODLCoin + ( + 1, + b"\x5b\x07\x51\x71\x3b\x25\x27\xd7\xf0\x02\xc0\xc4\xe2\xa3\x7e\x12\x19\x61\x0a\x6b", + "HORSE", + 18, + ), # eth / HORSE + ( + 1, + b"\x6c\x6e\xe5\xe3\x1d\x82\x8d\xe2\x41\x28\x2b\x96\x06\xc8\xe9\x8e\xa4\x85\x26\xe2", + "HOT", + 18, + ), # eth / HoloToken + ( + 1, + b"\x9a\xf8\x39\x68\x7f\x6c\x94\x54\x2a\xc5\xec\xe2\xe3\x17\xda\xae\x35\x54\x93\xa1", + "HOT", + 18, + ), # eth / Hydro Protocol + ( + 1, + b"\x55\x4c\x20\xb7\xc4\x86\xbe\xee\x43\x92\x77\xb4\x54\x0a\x43\x45\x66\xdc\x4c\x02", + "HST", + 18, + ), # eth / HST + ( + 1, + b"\xc0\xeb\x85\x28\x5d\x83\x21\x7c\xd7\xc8\x91\x70\x2b\xcb\xc0\xfc\x40\x1e\x2d\x9d", + "HVN", + 8, + ), # eth / Hive Project + ( + 1, + b"\xeb\xbd\xf3\x02\xc9\x40\xc6\xbf\xd4\x9c\x6b\x16\x5f\x45\x7f\xdb\x32\x46\x49\xbc", + "HYDRO", + 18, + ), # eth / Hydro + ( + 1, + b"\xc1\xe2\x09\x7d\x78\x8d\x33\x70\x1b\xa3\xcc\x27\x73\xbf\x67\x15\x5e\xc9\x3f\xc4", + "IAD", + 18, + ), # eth / IADOWR Coin + ( + 1, + b"\x5a\x84\x96\x9b\xb6\x63\xfb\x64\xf6\xd0\x15\xdc\xf9\xf6\x22\xae\xdc\x79\x67\x50", + "ICE", + 18, + ), # eth / ICE + ( + 1, + b"\x88\x86\x66\xca\x69\xe0\xf1\x78\xde\xd6\xd7\x5b\x57\x26\xce\xe9\x9a\x87\xd6\x98", + "ICN", + 18, + ), # eth / ICN + ( + 1, + b"\xa3\x3e\x72\x9b\xf4\xfd\xeb\x86\x8b\x53\x4e\x1f\x20\x52\x34\x63\xd9\xc4\x6b\xee", + "ICO", + 10, + ), # eth / ICO + ( + 1, + b"\x01\x4b\x50\x46\x65\x90\x34\x0d\x41\x30\x7c\xc5\x4d\xce\xe9\x90\xc8\xd5\x8a\xa8", + "ICOS", + 6, + ), # eth / ICOS + ( + 1, + b"\xb5\xa5\xf2\x26\x94\x35\x2c\x15\xb0\x03\x23\x84\x4a\xd5\x45\xab\xb2\xb1\x10\x28", + "ICX", + 18, + ), # eth / ICON + ( + 1, + b"\x81\x4c\xaf\xd4\x78\x2d\x2e\x72\x81\x70\xfd\xa6\x82\x57\x98\x3f\x03\x32\x1c\x58", + "IDEA", + 0, + ), # eth / IDEA Token + ( + 1, + b"\x76\x54\x91\x5a\x1b\x82\xd6\xd2\xd0\xaf\xc3\x7c\x52\xaf\x55\x6e\xa8\x98\x3c\x7e", + "IFT", + 18, + ), # eth / InvestFeed + ( + 1, + b"\x16\x66\x2f\x73\xdf\x3e\x79\xe5\x4c\x6c\x59\x38\xb4\x31\x3f\x92\xc5\x24\xc1\x20", + "IIC", + 18, + ), # eth / IIC + ( + 1, + b"\x88\xae\x96\x84\x5e\x15\x75\x58\xef\x59\xe9\xff\x90\xe7\x66\xe2\x2e\x48\x03\x90", + "IKB", + 0, + ), # eth / IKB + ( + 1, + b"\xe3\x83\x1c\x5a\x98\x2b\x27\x9a\x19\x84\x56\xd5\x77\xcf\xb9\x04\x24\xcb\x63\x40", + "IMC", + 6, + ), # eth / Immune Coin + ( + 1, + b"\x22\xe5\xf6\x2d\x0f\xa1\x99\x74\x74\x9f\xaa\x19\x4e\x3d\x3e\xf6\xd8\x9c\x08\xd7", + "IMT", + 0, + ), # eth / IMT + ( + 1, + b"\xf8\xe3\x86\xed\xa8\x57\x48\x4f\x5a\x12\xe4\xb5\xda\xa9\x98\x4e\x06\xe7\x37\x05", + "IND", + 18, + ), # eth / Indorse + ( + 1, + b"\x48\xe5\x41\x3b\x73\xad\xd2\x43\x4e\x47\x50\x4e\x2a\x22\xd1\x49\x40\xdb\xfe\x78", + "INRM", + 3, + ), # eth / Integrated Money + ( + 1, + b"\x5b\x2e\x4a\x70\x0d\xfb\xc5\x60\x06\x1e\x95\x7e\xde\xc8\xf6\xee\xeb\x74\xa3\x20", + "INS", + 10, + ), # eth / INS + ( + 1, + b"\xc7\x2f\xe8\xe3\xdd\x5b\xef\x0f\x9f\x31\xf2\x59\x39\x9f\x30\x12\x72\xef\x2a\x2d", + "INSTAR", + 18, + ), # eth / Insights Network + ( + 1, + b"\xa8\x00\x6c\x4c\xa5\x6f\x24\xd6\x83\x67\x27\xd1\x06\x34\x93\x20\xdb\x7f\xef\x82", + "INXT", + 8, + ), # eth / Internxt + ( + 1, + b"\xfa\x1a\x85\x6c\xfa\x34\x09\xcf\xa1\x45\xfa\x4e\x20\xeb\x27\x0d\xf3\xeb\x21\xab", + "IOST", + 18, + ), # eth / IOSToken + ( + 1, + b"\xc3\x4b\x21\xf6\xf8\xe5\x1c\xc9\x65\xc2\x39\x3b\x3c\xcf\xa3\xb8\x2b\xeb\x24\x03", + "IoT", + 6, + ), # eth / IoTコイン + ( + 1, + b"\x6f\xb3\xe0\xa2\x17\x40\x7e\xff\xf7\xca\x06\x2d\x46\xc2\x6e\x5d\x60\xa1\x4d\x69", + "IOTX", + 18, + ), # eth / IoTeX Network + ( + 1, + b"\x64\xcd\xf8\x19\xd3\xe7\x5a\xc8\xec\x21\x7b\x34\x96\xd7\xce\x16\x7b\xe4\x2e\x80", + "IPL", + 18, + ), # eth / InsurePal token + ( + 1, + b"\x00\x1f\x0a\xa5\xda\x15\x58\x5e\x5b\x23\x05\xdb\xab\x2b\xac\x42\x5e\xa7\x10\x07", + "IPSX", + 18, + ), # eth / IPSX + ( + 1, + b"\x5e\x6b\x6d\x9a\xba\xd9\x09\x3f\xdc\x86\x1e\xa1\x60\x0e\xba\x1b\x35\x5c\xd9\x40", + "ITC", + 18, + ), # eth / IoT Chain + ( + 1, + b"\x0a\xef\x06\xdc\xcc\xc5\x31\xe5\x81\xf0\x44\x00\x59\xe6\xff\xcc\x20\x60\x39\xee", + "ITT", + 8, + ), # eth / ITT Token + ( + 1, + b"\xfc\xa4\x79\x62\xd4\x5a\xdf\xdf\xd1\xab\x2d\x97\x23\x15\xdb\x4c\xe7\xcc\xf0\x94", + "IXT", + 8, + ), # eth / InsureX + ( + 1, + b"\x0d\x26\x2e\x5d\xc4\xa0\x6a\x0f\x1c\x90\xce\x79\xc7\xa6\x0c\x09\xdf\xc8\x84\xe4", + "J8T", + 8, + ), # eth / J8T Token + ( + 1, + b"\x0a\xaf\x56\x1e\xff\x5b\xd9\xc8\xf9\x11\x61\x69\x33\xf8\x41\x66\xa1\x7c\xfe\x0c", + "JBX", + 0, + ), # eth / JBX + ( + 1, + b"\x88\x4e\x39\x02\xc4\xd5\xcf\xa8\x6d\xe4\xac\xe7\xa9\x6a\xa9\x1e\xbc\x25\xc0\xff", + "JBX", + 18, + ), # eth / JBOX + ( + 1, + b"\x87\x27\xc1\x12\xc7\x12\xc4\xa0\x33\x71\xac\x87\xa7\x4d\xd6\xab\x10\x4a\xf7\x68", + "JET", + 18, + ), # eth / JET + ( + 1, + b"\x77\x34\x50\x33\x5e\xd4\xec\x3d\xb4\x5a\xf7\x4f\x34\xf2\xc8\x53\x48\x64\x5d\x39", + "JetCoins", + 18, + ), # eth / JetCoins + ( + 1, + b"\xa5\xfd\x1a\x79\x1c\x4d\xfc\xaa\xcc\x96\x3d\x4f\x73\xc6\xae\x58\x24\x14\x9e\xa7", + "JNT", + 18, + ), # eth / JNT + ( + 1, + b"\xdd\xe1\x2a\x12\xa6\xf6\x71\x56\xe0\xda\x67\x2b\xe0\x5c\x37\x4e\x1b\x0a\x3e\x57", + "JOY", + 6, + ), # eth / JOYSO + ( + 1, + b"\x0d\x6d\xd9\xf6\x8d\x24\xec\x1d\x5f\xe2\x17\x4f\x3e\xc8\xda\xb5\x2b\x52\xba\xf5", + "KC", + 18, + ), # eth / KMCC + ( + 1, + b"\x72\xd3\x2a\xc1\xc5\xe6\x6b\xfc\x5b\x08\x80\x62\x71\xf8\xee\xf9\x15\x54\x51\x64", + "KEE", + 0, + ), # eth / CryptoKEE + ( + 1, + b"\x4c\xc1\x93\x56\xf2\xd3\x73\x38\xb9\x80\x2a\xa8\xe8\xfc\x58\xb0\x37\x32\x96\xe7", + "KEY", + 18, + ), # eth / SelfKey + ( + 1, + b"\x4c\xd9\x88\xaf\xba\xd3\x72\x89\xba\xaf\x53\xc1\x3e\x98\xe2\xbd\x46\xaa\xea\x8c", + "KEY", + 18, + ), # eth / BihuKey + ( + 1, + b"\x27\x69\x5e\x09\x14\x9a\xdc\x73\x8a\x97\x8e\x9a\x67\x8f\x99\xe4\xc3\x9e\x9e\xb9", + "KICK", + 8, + ), # eth / KICK + ( + 1, + b"\x81\x8f\xc6\xc2\xec\x59\x86\xbc\x6e\x2c\xbf\x00\x93\x9d\x90\x55\x6a\xb1\x2c\xe5", + "KIN", + 18, + ), # eth / Kin Foundation + ( + 1, + b"\xdd\x97\x4d\x5c\x2e\x29\x28\xde\xa5\xf7\x1b\x98\x25\xb8\xb6\x46\x68\x6b\xd2\x00", + "KNC", + 18, + ), # eth / Kyber Network + ( + 1, + b"\xb5\xc3\x3f\x96\x5c\x88\x99\xd2\x55\xc3\x4c\xdd\x2a\x3e\xfa\x8a\xbc\xbb\x3d\xea", + "KPR", + 18, + ), # eth / KPRCoin + ( + 1, + b"\x46\x4e\xbe\x77\xc2\x93\xe4\x73\xb4\x8c\xfe\x96\xdd\xcf\x88\xfc\xf7\xbf\xda\xc0", + "KRL", + 18, + ), # eth / Kryll + ( + 1, + b"\x95\x41\xfd\x8b\x9b\x5f\xa9\x73\x81\x78\x37\x83\xce\xbf\x2f\x5f\xa7\x93\xc2\x62", + "KZN", + 8, + ), # eth / KaizenCoin + ( + 1, + b"\xe5\x03\x65\xf5\xd6\x79\xcb\x98\xa1\xdd\x62\xd6\xf6\xe5\x8e\x59\x32\x1b\xcd\xdf", + "LA", + 18, + ), # eth / LATOKEN + ( + 1, + b"\xfd\x10\x7b\x47\x3a\xb9\x0e\x8f\xbd\x89\x87\x21\x44\xa3\xdc\x92\xc4\x0f\xa8\xc9", + "LALA", + 18, + ), # eth / LALA World Token + ( + 1, + b"\x51\x02\x79\x1c\xa0\x2f\xc3\x59\x53\x98\x40\x0b\xfe\x0e\x33\xd7\xb6\xc8\x22\x67", + "LDC", + 18, + ), # eth / LEADCOIN + ( + 1, + b"\xd6\xe3\x54\xf0\x73\x19\xe2\x47\x44\x91\xd8\xc7\xc7\x12\x13\x7b\xee\x68\x62\xa2", + "LEMO", + 0, + ), # eth / Lemo + ( + 1, + b"\xb5\xae\x84\x8e\xdb\x29\x6c\x21\x25\x9b\x74\x67\x33\x14\x67\xd2\x64\x7e\xec\xdf", + "LEMO", + 18, + ), # eth / Lemo + ( + 1, + b"\x80\xfb\x78\x4b\x7e\xd6\x67\x30\xe8\xb1\xdb\xd9\x82\x0a\xfd\x29\x93\x1a\xab\x03", + "LEND", + 18, + ), # eth / EHTLend + ( + 1, + b"\xc7\x98\xcd\x1c\x49\xdb\x0e\x29\x73\x12\xe4\xc6\x82\x75\x26\x68\xce\x1d\xb2\xad", + "LFR", + 5, + ), # eth / LifeRun Coin + ( + 1, + b"\x12\x3a\xb1\x95\xdd\x38\xb1\xb4\x05\x10\xd4\x67\xa6\xa3\x59\xb2\x01\xaf\x05\x6f", + "LGO", + 8, + ), # eth / LGO + ( + 1, + b"\x2e\xb8\x6e\x8f\xc5\x20\xe0\xf6\xbb\x5d\x9a\xf0\x8f\x92\x4f\xe7\x05\x58\xab\x89", + "LGR", + 8, + ), # eth / Logarithm + ( + 1, + b"\xeb\x99\x51\x02\x16\x98\xb4\x2e\x43\x99\xf9\xcb\xb6\x26\x7a\xa3\x5f\x82\xd5\x9d", + "LIF", + 18, + ), # eth / LIF + ( + 1, + b"\xff\x18\xdb\xc4\x87\xb4\xc2\xe3\x22\x2d\x11\x59\x52\xba\xbf\xda\x8b\xa5\x2f\x5f", + "LIFE", + 18, + ), # eth / LIFE + ( + 1, + b"\x51\x49\x10\x77\x1a\xf9\xca\x65\x6a\xf8\x40\xdf\xf8\x3e\x82\x64\xec\xf9\x86\xca", + "LINK (Chainlink)", + 18, + ), # eth / LINK Chainlink + ( + 1, + b"\xe2\xe6\xd4\xbe\x08\x6c\x69\x38\xb5\x3b\x22\x14\x48\x55\xee\xf6\x74\x28\x16\x39", + "LINK Platform", + 18, + ), # eth / Link Platform + ( + 1, + b"\x24\xa7\x7c\x1f\x17\xc5\x47\x10\x5e\x14\x81\x3e\x51\x7b\xe0\x6b\x00\x40\xaa\x76", + "LIVE", + 18, + ), # eth / LIVE Token + ( + 1, + b"\x63\xe6\x34\x33\x0a\x20\x15\x0d\xbb\x61\xb1\x56\x48\xbc\x73\x85\x5d\x6c\xcf\x07", + "LNC", + 18, + ), # eth / Lancer Token + ( + 1, + b"\x6b\xeb\x41\x8f\xc6\xe1\x95\x82\x04\xac\x8b\xad\xdc\xf1\x09\xb8\xe9\x69\x49\x66", + "LNC-Linker Coin", + 18, + ), # eth / Linker Coin + ( + 1, + b"\x09\x47\xb0\xe6\xd8\x21\x37\x88\x05\xc9\x59\x82\x91\x38\x5c\xe7\xc7\x91\xa6\xb2", + "LND", + 18, + ), # eth / Lendingblock + ( + 1, + b"\x5e\x33\x46\x44\x40\x10\x13\x53\x22\x26\x8a\x46\x30\xd2\xed\x5f\x8d\x09\x44\x6c", + "LOC", + 18, + ), # eth / LockChain + ( + 1, + b"\x9c\x23\xd6\x7a\xea\x7b\x95\xd8\x09\x42\xe3\x83\x6b\xcd\xf7\xe7\x08\xa7\x47\xc2", + "LOCI", + 18, + ), # eth / LOCIcoin + ( + 1, + b"\xc6\x45\x00\xdd\x7b\x0f\x17\x94\x80\x7e\x67\x80\x2f\x8a\xbb\xf5\xf8\xff\xb0\x54", + "LOCUS", + 18, + ), # eth / Locus Chain + ( + 1, + b"\x21\xae\x23\xb8\x82\xa3\x40\xa2\x22\x82\x16\x20\x86\xbc\x98\xd3\xe2\xb7\x30\x18", + "LOK", + 18, + ), # eth / LOK + ( + 1, + b"\xa4\xe8\xc3\xec\x45\x61\x07\xea\x67\xd3\x07\x5b\xf9\xe3\xdf\x3a\x75\x82\x3d\xb0", + "LOOM", + 18, + ), # eth / LOOM + ( + 1, + b"\x58\xb6\xa8\xa3\x30\x23\x69\xda\xec\x38\x33\x34\x67\x24\x04\xee\x73\x3a\xb2\x39", + "LPT", + 18, + ), # eth / Livepeer Token + ( + 1, + b"\xef\x68\xe7\xc6\x94\xf4\x0c\x82\x02\x82\x1e\xdf\x52\x5d\xe3\x78\x24\x58\x63\x9f", + "LRC", + 18, + ), # eth / LRC + ( + 1, + b"\x5d\xbe\x29\x6f\x97\xb2\x3c\x4a\x6a\xa6\x18\x3d\x73\xe5\x74\xd0\x2b\xa5\xc7\x19", + "LUC", + 18, + ), # eth / LUCToken + ( + 1, + b"\xfb\x12\xe3\xcc\xa9\x83\xb9\xf5\x9d\x90\x91\x2f\xd1\x7f\x8d\x74\x5a\x8b\x29\x53", + "LUCK", + 0, + ), # eth / LUCK + ( + 1, + b"\xa8\x9b\x59\x34\x86\x34\x47\xf6\xe4\xfc\x53\xb3\x15\xa9\x3e\x87\x3b\xda\x69\xa3", + "LUM", + 18, + ), # eth / Lumino Coin + ( + 1, + b"\xfa\x05\xa7\x3f\xfe\x78\xef\x8f\x1a\x73\x94\x73\xe4\x62\xc5\x4b\xae\x65\x67\xd9", + "LUN", + 18, + ), # eth / LUN + ( + 1, + b"\xdd\x41\xfb\xd1\xae\x95\xc5\xd9\xb1\x98\x17\x4a\x28\xe0\x4b\xe6\xb3\xd1\xaa\x27", + "LYS", + 8, + ), # eth / Lightyears + ( + 1, + b"\x3f\x4b\x72\x66\x68\xda\x46\xf5\xe0\xe7\x5a\xa5\xd4\x78\xac\xec\x9f\x38\x21\x0f", + "M-ETH", + 18, + ), # eth / M-ETH + ( + 1, + b"\x5b\x09\xa0\x37\x1c\x1d\xa4\x4a\x8e\x24\xd3\x6b\xf5\xde\xb1\x14\x1a\x84\xd8\x75", + "MAD", + 18, + ), # eth / MAD + ( + 1, + b"\xe2\x5b\xce\xc5\xd3\x80\x1c\xe3\xa7\x94\x07\x9b\xf9\x4a\xdf\x1b\x8c\xcd\x80\x2d", + "MAN", + 18, + ), # eth / MAN + ( + 1, + b"\x0f\x5d\x2f\xb2\x9f\xb7\xd3\xcf\xee\x44\x4a\x20\x02\x98\xf4\x68\x90\x8c\xc9\x42", + "MANA", + 18, + ), # eth / Decentraland MANA + ( + 1, + b"\xfd\xcc\x07\xab\x60\x66\x0d\xe5\x33\xb5\xad\x26\xe1\x45\x7b\x56\x5a\x9d\x59\xbd", + "MART", + 18, + ), # eth / Martcoin + ( + 1, + b"\x38\x64\x67\xf1\xf3\xdd\xbe\x83\x24\x48\x65\x04\x18\x31\x1a\x47\x9e\xec\xfc\x57", + "MBRS", + 0, + ), # eth / Embers + ( + 1, + b"\x93\xe6\x82\x10\x7d\x1e\x9d\xef\xb0\xb5\xee\x70\x1c\x71\x70\x7a\x4b\x2e\x46\xbc", + "MCAP", + 8, + ), # eth / MCAP + ( + 1, + b"\x13\x8a\x87\x52\x09\x3f\x4f\x9a\x79\xaa\xed\xf4\x8d\x4b\x92\x48\xfa\xb9\x3c\x9c", + "MCI", + 18, + ), # eth / Musiconomi + ( + 1, + b"\xb6\x3b\x60\x6a\xc8\x10\xa5\x2c\xca\x15\xe4\x4b\xb6\x30\xfd\x42\xd8\xd1\xd8\x3d", + "MCO", + 8, + ), # eth / MCO + ( + 1, + b"\x51\xdb\x5a\xd3\x5c\x67\x1a\x87\x20\x7d\x88\xfc\x11\xd5\x93\xac\x0c\x84\x15\xbd", + "MDA", + 18, + ), # eth / MDA + ( + 1, + b"\x01\xf2\xac\xf2\x91\x48\x60\x33\x1c\x1c\xb1\xa9\xac\xec\xda\x74\x75\xe0\x6a\xf8", + "MESH", + 18, + ), # eth / Meshbox + ( + 1, + b"\x5b\x8d\x43\xff\xde\x4a\x29\x82\xb9\xa5\x38\x7c\xdf\x21\xd5\x4e\xad\x64\xac\x8d", + "MEST", + 18, + ), # eth / Monaco Estate + ( + 1, + b"\x67\x10\xc6\x34\x32\xa2\xde\x02\x95\x4f\xc0\xf8\x51\xdb\x07\x14\x6a\x6c\x03\x12", + "MFG", + 18, + ), # eth / SyncFab Smart Manufacturing Blockchain + ( + 1, + b"\x40\x39\x50\x44\xac\x3c\x0c\x57\x05\x19\x06\xda\x93\x8b\x54\xbd\x65\x57\xf2\x12", + "MGO", + 8, + ), # eth / MGO + ( + 1, + b"\xe2\x3c\xd1\x60\x76\x1f\x63\xfc\x3a\x1c\xf7\x8a\xa0\x34\xb6\xcd\xf9\x7d\x3e\x0c", + "MIT", + 18, + ), # eth / MIT + ( + 1, + b"\xad\x8d\xd4\xc7\x25\xde\x1d\x31\xb9\xe8\xf8\xd1\x46\x08\x9e\x9d\xc6\x88\x20\x93", + "MIT (Mychatcoin)", + 6, + ), # eth / Mychatcoin + ( + 1, + b"\x9f\x8f\x72\xaa\x93\x04\xc8\xb5\x93\xd5\x55\xf1\x2e\xf6\x58\x9c\xc3\xa5\x79\xa2", + "MKR", + 18, + ), # eth / MakerDAO + ( + 1, + b"\x79\x39\x88\x2b\x54\xfc\xf0\xbc\xae\x6b\x53\xde\xc3\x9a\xd6\xe8\x06\x17\x64\x42", + "MKT", + 8, + ), # eth / Mikado + ( + 1, + b"\xbe\xb9\xef\x51\x4a\x37\x9b\x99\x7e\x07\x98\xfd\xcc\x90\x1e\xe4\x74\xb6\xd9\xa1", + "MLN", + 18, + ), # eth / Melonport + ( + 1, + b"\x1a\x95\xb2\x71\xb0\x53\x5d\x15\xfa\x49\x93\x2d\xab\xa3\x1b\xa6\x12\xb5\x29\x46", + "MNE", + 8, + ), # eth / MNE + ( + 1, + b"\xa9\x87\x7b\x1e\x05\xd0\x35\x89\x91\x31\xdb\xd1\xe4\x03\x82\x51\x66\xd0\x9f\x92", + "MNT", + 18, + ), # eth / Media Network Token + ( + 1, + b"\x83\xce\xe9\xe0\x86\xa7\x7e\x49\x2e\xe0\xbb\x93\xc2\xb0\x43\x7a\xd6\xfd\xec\xcc", + "MNTP", + 18, + ), # eth / Goldmint MNT Prelaunch Token + ( + 1, + b"\x95\x7c\x30\xab\x04\x26\xe0\xc9\x3c\xd8\x24\x1e\x2c\x60\x39\x2d\x08\xc6\xac\x8e", + "MOD", + 0, + ), # eth / Modum + ( + 1, + b"\x82\x12\x5a\xfe\x01\x81\x9d\xff\x15\x35\xd0\xd6\x27\x6d\x57\x04\x52\x91\xb6\xc0", + "MRL", + 18, + ), # eth / Marcelo + ( + 1, + b"\x21\xf0\xf0\xfd\x31\x41\xee\x9e\x11\xb3\xd7\xf1\x3a\x10\x28\xcd\x51\x5f\x45\x9c", + "MRP", + 18, + ), # eth / MoneyRebel Token + ( + 1, + b"\xab\x6c\xf8\x7a\x50\xf1\x7d\x7f\x5e\x1f\xea\xf8\x1b\x6f\xe9\xff\xbe\x8e\xbf\x84", + "MRV", + 18, + ), # eth / MRV + ( + 1, + b"\x68\xaa\x3f\x23\x2d\xa9\xbd\xc2\x34\x34\x65\x54\x57\x94\xef\x3e\xea\x52\x09\xbd", + "MSP", + 18, + ), # eth / Mothership + ( + 1, + b"\x90\x5e\x33\x7c\x6c\x86\x45\x26\x3d\x35\x21\x20\x5a\xa3\x7b\xf4\xd0\x34\xe7\x45", + "MTC", + 18, + ), # eth / Medical Token Currency + ( + 1, + b"\xaf\x4d\xce\x16\xda\x28\x77\xf8\xc9\xe0\x05\x44\xc9\x3b\x62\xac\x40\x63\x1f\x16", + "MTH", + 5, + ), # eth / Monetha + ( + 1, + b"\xf4\x33\x08\x93\x66\x89\x9d\x83\xa9\xf2\x6a\x77\x3d\x59\xec\x7e\xcf\x30\x35\x5e", + "MTL", + 8, + ), # eth / MetalPay + ( + 1, + b"\x41\xdb\xec\xc1\xcd\xc5\x51\x7c\x6f\x76\xf6\xa6\xe8\x36\xad\xbe\xe2\x75\x4d\xe3", + "MTN", + 18, + ), # eth / MedToken + ( + 1, + b"\x7f\xc4\x08\x01\x11\x65\x76\x0e\xe3\x1b\xe2\xbf\x20\xda\xf4\x50\x35\x66\x92\xaf", + "MTR", + 8, + ), # eth / Mitrav + ( + 1, + b"\x1e\x49\xff\x77\xc3\x55\xa3\xe3\x8d\x66\x51\xce\x84\x04\xaf\x0e\x48\xc5\x39\x5f", + "MTRc", + 18, + ), # eth / MTRCToken + ( + 1, + b"\x0a\xf4\x4e\x27\x84\x63\x72\x18\xdd\x1d\x32\xa3\x22\xd4\x4e\x60\x3a\x8f\x0c\x6a", + "MTX", + 18, + ), # eth / MTX + ( + 1, + b"\x51\x56\x69\xd3\x08\xf8\x87\xfd\x83\xa4\x71\xc7\x76\x4f\x5d\x08\x48\x86\xd3\x4d", + "MUXE", + 18, + ), # eth / MUXE + ( + 1, + b"\x8a\x77\xe4\x09\x36\xbb\xc2\x7e\x80\xe9\xa3\xf5\x26\x36\x8c\x96\x78\x69\xc8\x6d", + "MVP", + 18, + ), # eth / Merculet + ( + 1, + b"\x64\x25\xc6\xbe\x90\x2d\x69\x2a\xe2\xdb\x75\x2b\x3c\x26\x8a\xfa\xdb\x09\x9d\x3b", + "MWAT", + 18, + ), # eth / RED MWAT + ( + 1, + b"\xf7\xe9\x83\x78\x16\x09\x01\x23\x07\xf2\x51\x4f\x63\xd5\x26\xd8\x3d\x24\xf4\x66", + "MYD", + 16, + ), # eth / MYD + ( + 1, + b"\xa6\x45\x26\x4c\x56\x03\xe9\x6c\x3b\x0b\x07\x8c\xda\xb6\x87\x33\x79\x4b\x0a\x71", + "MYST", + 8, + ), # eth / Mysterium + ( + 1, + b"\x8d\x80\xde\x8a\x78\x19\x83\x96\x32\x9d\xfa\x76\x9a\xd5\x4d\x24\xbf\x90\xe7\xaa", + "NAC", + 18, + ), # eth / Nami ICO + ( + 1, + b"\xff\xe0\x2e\xe4\xc6\x9e\xdf\x1b\x34\x0f\xca\xd6\x4f\xbd\x6b\x37\xa7\xb9\xe2\x65", + "NANJ", + 8, + ), # eth / NANJCOIN + ( + 1, + b"\x58\x80\x47\x36\x5d\xf5\xba\x58\x9f\x92\x36\x04\xaa\xc2\x3d\x67\x35\x55\xc6\x23", + "NAVI", + 18, + ), # eth / NaviToken + ( + 1, + b"\x17\xf8\xaf\xb6\x3d\xfc\xdc\xc9\x0e\xbe\x6e\x84\xf0\x60\xcc\x30\x6a\x98\x25\x7d", + "NBAI", + 18, + ), # eth / NebulaAiToken + ( + 1, + b"\x80\x98\x26\xcc\xea\xb6\x8c\x38\x77\x26\xaf\x96\x27\x13\xb6\x4c\xb5\xcb\x3c\xca", + "nCash", + 18, + ), # eth / NucleusVision + ( + 1, + b"\x9e\x46\xa3\x8f\x5d\xaa\xbe\x86\x83\xe1\x07\x93\xb0\x67\x49\xee\xf7\xd7\x33\xd1", + "NCT", + 18, + ), # eth / Nectar + ( + 1, + b"\xa5\x4d\xdc\x7b\x3c\xce\x7f\xc8\xb1\xe3\xfa\x02\x56\xd0\xdb\x80\xd2\xc1\x09\x70", + "NDC", + 18, + ), # eth / Neverdie + ( + 1, + b"\xcc\x80\xc0\x51\x05\x7b\x77\x4c\xd7\x50\x67\xdc\x48\xf8\x98\x7c\x4e\xb9\x7a\x5e", + "NEC", + 18, + ), # eth / Ethfinex Nectar Token + ( + 1, + b"\xcf\xb9\x86\x37\xbc\xae\x43\xc1\x33\x23\xea\xa1\x73\x1c\xed\x2b\x71\x69\x62\xfd", + "NET", + 18, + ), # eth / NIMIQ + ( + 1, + b"\xa8\x23\xe6\x72\x20\x06\xaf\xe9\x9e\x91\xc3\x0f\xf5\x29\x50\x52\xfe\x6b\x8e\x32", + "NEU", + 18, + ), # eth / NEU Fund + ( + 1, + b"\x72\xdd\x4b\x6b\xd8\x52\xa3\xaa\x17\x2b\xe4\xd6\xc5\xa6\xdb\xec\x58\x8c\xf1\x31", + "NGC", + 18, + ), # eth / NAGA Coin + ( + 1, + b"\xe2\x65\x17\xa9\x96\x72\x99\x45\x3d\x3f\x1b\x48\xaa\x00\x5e\x61\x27\xe6\x72\x10", + "NIMFA", + 18, + ), # eth / Ninfa Money + ( + 1, + b"\x17\x76\xe1\xf2\x6f\x98\xb1\xa5\xdf\x9c\xd3\x47\x95\x3a\x26\xdd\x3c\xb4\x66\x71", + "NMR", + 18, + ), # eth / NMR + ( + 1, + b"\x64\x3b\x68\x70\xbe\xab\xee\x94\x1b\x92\x60\xa0\xa8\x78\xbc\xf4\xa6\x1f\xb0\xf1", + "NONE", + 0, + ), # eth / None + ( + 1, + b"\xec\x46\xf8\x20\x7d\x76\x60\x12\x45\x4c\x40\x8d\xe2\x10\xbc\xbc\x22\x43\xe7\x1c", + "NOX", + 18, + ), # eth / NOX + ( + 1, + b"\x4c\xe6\xb3\x62\xbc\x77\xa2\x49\x66\xdd\xa9\x07\x8f\x9c\xef\x81\xb3\xb8\x86\xa7", + "NPER", + 18, + ), # eth / NPER + ( + 1, + b"\xa1\x5c\x7e\xbe\x1f\x07\xca\xf6\xbf\xf0\x97\xd8\xa5\x89\xfb\x8a\xc4\x9a\xe5\xb3", + "NPXS", + 18, + ), # eth / Pundi X Token + ( + 1, + b"\xb9\x13\x18\xf3\x5b\xdb\x26\x2e\x94\x23\xbc\x7c\x7c\x2a\x3a\x93\xdd\x93\xc9\x2c", + "NULS", + 18, + ), # eth / NULS + ( + 1, + b"\x57\xab\x1e\x02\xfe\xe2\x37\x74\x58\x0c\x11\x97\x40\x12\x9e\xac\x70\x81\xe9\xd3", + "nUSD", + 18, + ), # eth / Havven-Backed USD Nomins (nUSD) + ( + 1, + b"\x45\xe4\x2d\x65\x9d\x9f\x94\x66\xcd\x5d\xf6\x22\x50\x60\x33\x14\x5a\x9b\x89\xbc", + "NxC", + 3, + ), # eth / Nexium + ( + 1, + b"\x76\x27\xde\x4b\x93\x26\x3a\x6a\x75\x70\xb8\xda\xfa\x64\xba\xe8\x12\xe5\xc3\x94", + "NXX", + 8, + ), # eth / NXX + ( + 1, + b"\x5c\x61\x83\xd1\x0a\x00\xcd\x74\x7a\x6d\xbb\x5f\x65\x8a\xd5\x14\x38\x3e\x94\x19", + "NXX OLD", + 8, + ), # eth / NXX OLD + ( + 1, + b"\x5e\x88\x8b\x83\xb7\x28\x7e\xed\x4f\xb7\xda\x7b\x7d\x0a\x0d\x4c\x73\x5d\x94\xb3", + "OAK", + 18, + ), # eth / OAK + ( + 1, + b"\x70\x1c\x24\x4b\x98\x8a\x51\x3c\x94\x59\x73\xde\xfa\x05\xde\x93\x3b\x23\xfe\x1d", + "OAX", + 18, + ), # eth / OAX + ( + 1, + b"\x02\x35\xfe\x62\x4e\x04\x4a\x05\xee\xd7\xa4\x3e\x16\xe3\x08\x3b\xc8\xa4\x28\x7a", + "OCC", + 18, + ), # eth / Original Crypto Coin + ( + 1, + b"\x6f\x53\x9a\x94\x56\xa5\xbc\xb6\x33\x4a\x1a\x41\x20\x7c\x37\x88\xf5\x82\x52\x07", + "OHNI", + 18, + ), # eth / Ohni + ( + 1, + b"\x7f\x21\x76\xce\xb1\x6d\xcb\x64\x8d\xc9\x24\xef\xf6\x17\xc3\xdc\x2b\xef\xd3\x0d", + "OHNI", + 0, + ), # eth / OHNI + ( + 1, + b"\xbe\xef\x54\x6a\xc8\xa4\xe0\xa8\x0d\xc1\xe2\xd6\x96\x96\x8e\xf5\x41\x38\xf1\xd4", + "OJX", + 18, + ), # eth / Ojooo Coin + ( + 1, + b"\xc6\x6e\xa8\x02\x71\x7b\xfb\x98\x33\x40\x02\x64\xdd\x12\xc2\xbc\xea\xa3\x4a\x6d", + "OLD_MKR", + 18, + ), # eth / MakerDAO + ( + 1, + b"\xd2\x61\x14\xcd\x6e\xe2\x89\xac\xcf\x82\x35\x0c\x8d\x84\x87\xfe\xdb\x8a\x0c\x07", + "OMG", + 18, + ), # eth / OMG + ( + 1, + b"\xb2\x3b\xe7\x35\x73\xbc\x7e\x03\xdb\x6e\x5d\xfc\x62\x40\x53\x68\x71\x6d\x28\xa8", + "ONEK", + 18, + ), # eth / One K Token + ( + 1, + b"\xd3\x41\xd1\x68\x0e\xee\xe3\x25\x5b\x8c\x4c\x75\xbc\xce\x7e\xb5\x7f\x14\x4d\xae", + "onG", + 18, + ), # eth / onG + ( + 1, + b"\x69\xc4\xbb\x24\x0c\xf0\x5d\x51\xee\xab\x69\x85\xba\xb3\x55\x27\xd0\x4a\x8c\x64", + "OPEN", + 8, + ), # eth / OPEN + ( + 1, + b"\xe9\xde\x1c\x63\x07\x53\xa1\x5d\x70\x21\xcc\x56\x34\x29\xc2\x1d\x48\x87\x50\x6f", + "OPEN", + 8, + ), # eth / OPEN + ( + 1, + b"\x43\x55\xfc\x16\x0f\x74\x32\x8f\x9b\x38\x3d\xf2\xec\x58\x9b\xb3\xdf\xd8\x2b\xa0", + "OPT", + 18, + ), # eth / Opus Foundation + ( + 1, + b"\xff\x56\xcc\x6b\x1e\x6d\xed\x34\x7a\xa0\xb7\x67\x6c\x85\xab\x0b\x3d\x08\xb0\xfa", + "ORBS", + 18, + ), # eth / Orbs + ( + 1, + b"\x2c\x4e\x8f\x2d\x74\x61\x13\xd0\x69\x6c\xe8\x9b\x35\xf0\xd8\xbf\x88\xe0\xae\xca", + "OST", + 18, + ), # eth / Simple Token 'OST' + ( + 1, + b"\x65\xa1\x50\x14\x96\x4f\x21\x02\xff\x58\x64\x7e\x16\xa1\x6a\x6b\x9e\x14\xbc\xf6", + "Ox Fina", + 3, + ), # eth / Ox Fina + ( + 1, + b"\xfe\xda\xe5\x64\x26\x68\xf8\x63\x6a\x11\x98\x7f\xf3\x86\xbf\xd2\x15\xf9\x42\xee", + "PAL", + 18, + ), # eth / PolicyPal Network + ( + 1, + b"\xea\x5f\x88\xe5\x4d\x98\x2c\xbb\x0c\x44\x1c\xde\x4e\x79\xbc\x30\x5e\x5b\x43\xbc", + "PARETO", + 18, + ), # eth / PARETO + ( + 1, + b"\xbb\x1f\xa4\xfd\xeb\x34\x59\x73\x3b\xf6\x7e\xbc\x6f\x89\x30\x03\xfa\x97\x6a\x82", + "PAT", + 18, + ), # eth / Pangea Arbitration Token + ( + 1, + b"\x69\x44\x04\x59\x5e\x30\x75\xa9\x42\x39\x7f\x46\x6a\xac\xd4\x62\xff\x1a\x7b\xd0", + "PATENTS", + 18, + ), # eth / PATENTS + ( + 1, + b"\xf8\x13\xf3\x90\x2b\xbc\x00\xa6\xdc\xe3\x78\x63\x4d\x3b\x79\xd8\x4f\x98\x03\xd7", + "PATH", + 18, + ), # eth / PATH + ( + 1, + b"\xb9\x70\x48\x62\x8d\xb6\xb6\x61\xd4\xc2\xaa\x83\x3e\x95\xdb\xe1\xa9\x05\xb2\x80", + "PAY", + 18, + ), # eth / TenX + ( + 1, + b"\x55\x64\x8d\xe1\x98\x36\x33\x85\x49\x13\x0b\x1a\xf5\x87\xf1\x6b\xea\x46\xf6\x6b", + "PBL", + 18, + ), # eth / PBL + ( + 1, + b"\xf4\xc0\x7b\x18\x65\xbc\x32\x6a\x3c\x01\x33\x94\x92\xca\x75\x38\xfd\x03\x8c\xc0", + "PBT", + 4, + ), # eth / Primalbase Token (PBT) + ( + 1, + b"\xfc\xac\x7a\x75\x15\xe9\xa9\xd7\x61\x9f\xa7\x7a\x1f\xa7\x38\x11\x1f\x66\x72\x7e", + "PCH", + 18, + ), # eth / PITCH + ( + 1, + b"\x36\x18\x51\x6f\x45\xcd\x3c\x91\x3f\x81\xf9\x98\x7a\xf4\x10\x77\x93\x2b\xc4\x0d", + "PCL", + 8, + ), # eth / Peculium + ( + 1, + b"\x53\x14\x8b\xb4\x55\x17\x07\xed\xf5\x1a\x1e\x8d\x7a\x93\x69\x8d\x18\x93\x12\x25", + "PCLOLD", + 8, + ), # eth / PeculiumOLD + ( + 1, + b"\x58\x84\x96\x9e\xc0\x48\x05\x56\xe1\x1d\x11\x99\x80\x13\x6a\x4c\x17\xed\xde\xd1", + "PET", + 18, + ), # eth / PETHEREUM + ( + 1, + b"\xec\x18\xf8\x98\xb4\x07\x6a\x3e\x18\xf1\x08\x9d\x33\x37\x6c\xc3\x80\xbd\xe6\x1d", + "PETRO", + 18, + ), # eth / PETRO + ( + 1, + b"\x55\xc2\xa0\xc1\x71\xd9\x20\x84\x35\x60\x59\x4d\xe3\xd6\xee\xcc\x09\xef\xc0\x98", + "PEXT", + 4, + ), # eth / PEX-Token + ( + 1, + b"\xe6\x45\x09\xf0\xbf\x07\xce\x2d\x29\xa7\xef\x19\xa8\xa9\xbc\x06\x54\x77\xc1\xb4", + "PIPL", + 8, + ), # eth / PIPL Coin + ( + 1, + b"\x8e\xff\xd4\x94\xeb\x69\x8c\xc3\x99\xaf\x62\x31\xfc\xcd\x39\xe0\x8f\xd2\x0b\x15", + "PIX", + 0, + ), # eth / PIX + ( + 1, + b"\x59\x41\x6a\x25\x62\x8a\x76\xb4\x73\x0e\xc5\x14\x86\x11\x4c\x32\xe0\xb5\x82\xa1", + "PLASMA", + 6, + ), # eth / PLASMA + ( + 1, + b"\xe4\x77\x29\x2f\x1b\x32\x68\x68\x7a\x29\x37\x61\x16\xb0\xed\x27\xa9\xc7\x61\x70", + "PLAY", + 18, + ), # eth / HeroCoin + ( + 1, + b"\x0a\xff\xa0\x6e\x7f\xbe\x5b\xc9\xa7\x64\xc9\x79\xaa\x66\xe8\x25\x6a\x63\x1f\x02", + "PLBT", + 6, + ), # eth / Polybius + ( + 1, + b"\xe3\x81\x85\x04\xc1\xb3\x2b\xf1\x55\x7b\x16\xc2\x38\xb2\xe0\x1f\xd3\x14\x9c\x17", + "PLR", + 18, + ), # eth / Pillar Project + ( + 1, + b"\xd8\x91\x2c\x10\x68\x1d\x8b\x21\xfd\x37\x42\x24\x4f\x44\x65\x8d\xba\x12\x26\x4e", + "PLU", + 18, + ), # eth / Plutus + ( + 1, + b"\x0e\x09\x89\xb1\xf9\xb8\xa3\x89\x83\xc2\xba\x80\x53\x26\x9c\xa6\x2e\xc9\xb1\x95", + "POE", + 8, + ), # eth / Po.et Tokens + ( + 1, + b"\x43\xf6\xa1\xbe\x99\x2d\xee\x40\x87\x21\x74\x84\x90\x77\x2b\x15\x14\x3c\xe0\xa7", + "POIN", + 0, + ), # eth / Potatoin + ( + 1, + b"\x99\x92\xec\x3c\xf6\xa5\x5b\x00\x97\x8c\xdd\xf2\xb2\x7b\xc6\x88\x2d\x88\xd1\xec", + "POLY", + 18, + ), # eth / Polymath Network + ( + 1, + b"\x77\x9b\x7b\x71\x3c\x86\xe3\xe6\x77\x4f\x50\x40\xd9\xcc\xc2\xd4\x3a\xd3\x75\xf8", + "POOL", + 8, + ), # eth / Stake Pool + ( + 1, + b"\xee\x60\x9f\xe2\x92\x12\x8c\xad\x03\xb7\x86\xdb\xb9\xbc\x26\x34\xcc\xdb\xe7\xfc", + "POS", + 18, + ), # eth / PoSToken + ( + 1, + b"\x59\x58\x32\xf8\xfc\x6b\xf5\x9c\x85\xc5\x27\xfe\xc3\x74\x0a\x1b\x7a\x36\x12\x69", + "POWR", + 6, + ), # eth / PowerLedger + ( + 1, + b"\xc4\x22\x09\xac\xcc\x14\x02\x9c\x10\x12\xfb\x56\x80\xd9\x5f\xbd\x60\x36\xe2\xa0", + "PPP", + 18, + ), # eth / PayPie + ( + 1, + b"\xd4\xfa\x14\x60\xf5\x37\xbb\x90\x85\xd2\x2c\x7b\xcc\xb5\xdd\x45\x0e\xf2\x8e\x3a", + "PPT", + 8, + ), # eth / Populous + ( + 1, + b"\x88\xa3\xe4\xf3\x5d\x64\xaa\xd4\x1a\x6d\x40\x30\xac\x9a\xfe\x43\x56\xcb\x84\xfa", + "PRE", + 18, + ), # eth / Presearch + ( + 1, + b"\x77\x28\xdf\xef\x5a\xbd\x46\x86\x69\xeb\x7f\x9b\x48\xa7\xf7\x0a\x50\x1e\xd2\x9d", + "PRG", + 6, + ), # eth / PRG + ( + 1, + b"\x18\x44\xb2\x15\x93\x26\x26\x68\xb7\x24\x8d\x0f\x57\xa2\x20\xca\xab\xa4\x6a\xb9", + "PRL", + 18, + ), # eth / Oyster Pearl + ( + 1, + b"\x22\x6b\xb5\x99\xa1\x2c\x82\x64\x76\xe3\xa7\x71\x45\x46\x97\xea\x52\xe9\xe2\x20", + "PRO", + 8, + ), # eth / Propy + ( + 1, + b"\xa3\x14\x9e\x0f\xa0\x06\x1a\x90\x07\xfa\xf3\x07\x07\x4c\xdc\xd2\x90\xf0\xe2\xfd", + "PRON", + 8, + ), # eth / PronCoin + ( + 1, + b"\x76\x41\xb2\xca\x9d\xdd\x58\xad\xdf\x6e\x33\x81\xc1\xf9\x94\xaa\xc5\xf1\xa3\x2f", + "PRPS", + 18, + ), # eth / Purpose + ( + 1, + b"\xd9\x4f\x27\x78\xe2\xb3\x91\x3c\x53\x63\x7a\xe6\x06\x47\x59\x8b\xe5\x88\xc5\x70", + "PRPS", + 18, + ), # eth / Purpose + ( + 1, + b"\x16\x37\x33\xbc\xc2\x8d\xbf\x26\xb4\x1a\x8c\xfa\x83\xe3\x69\xb5\xb3\xaf\x74\x1b", + "PRS", + 18, + ), # eth / Persians + ( + 1, + b"\x0c\x04\xd4\xf3\x31\xda\x8d\xf7\x5f\x9e\x2e\x27\x1e\x3f\x3f\x14\x94\xc6\x6c\x36", + "PRSP", + 9, + ), # eth / PRSP + ( + 1, + b"\x66\x49\x7a\x28\x3e\x0a\x00\x7b\xa3\x97\x4e\x83\x77\x84\xc6\xae\x32\x34\x47\xde", + "PT", + 18, + ), # eth / PornToken + ( + 1, + b"\x2a\x8e\x98\xe2\x56\xf3\x22\x59\xb5\xe5\xcb\x55\xdd\x63\xc8\xe8\x91\x95\x06\x66", + "PTC", + 18, + ), # eth / ParrotCoin + ( + 1, + b"\x8a\xe4\xbf\x2c\x33\xa8\xe6\x67\xde\x34\xb5\x49\x38\xb0\xcc\xd0\x3e\xb8\xcc\x06", + "PTOY", + 8, + ), # eth / PTOY + ( + 1, + b"\x55\x12\xe1\xd6\xa7\xbe\x42\x4b\x43\x23\x12\x6b\x4f\x9e\x86\xd0\x23\xf9\x57\x64", + "PTWO", + 18, + ), # eth / PornTokenV2 + ( + 1, + b"\xef\x6b\x4c\xe8\xc9\xbc\x83\x74\x4f\xbc\xde\x26\x57\xb3\x2e\xc1\x87\x90\x45\x8a", + "PUC", + 0, + ), # eth / Pour Coin + ( + 1, + b"\xc1\x48\x30\xe5\x3a\xa3\x44\xe8\xc1\x46\x03\xa9\x12\x29\xa0\xb9\x25\xb0\xb2\x62", + "PXT", + 8, + ), # eth / Populous XBRL Token (PXT) + ( + 1, + b"\x61\x8e\x75\xac\x90\xb1\x2c\x60\x49\xba\x3b\x27\xf5\xd5\xf8\x65\x1b\x00\x37\xf6", + "QASH", + 6, + ), # eth / QASH + ( + 1, + b"\x67\x1a\xbb\xe5\xce\x65\x24\x91\x98\x53\x42\xe8\x54\x28\xeb\x1b\x07\xbc\x6c\x64", + "QAU", + 8, + ), # eth / QAU + ( + 1, + b"\x24\x67\xaa\x6b\x5a\x23\x51\x41\x6f\xd4\xc3\xde\xf8\x46\x2d\x84\x1f\xee\xec\xec", + "QBX", + 18, + ), # eth / qiibeeToken + ( + 1, + b"\xff\xaa\x5f\xfc\x45\x5d\x91\x31\xf8\xa2\x71\x3a\x74\x1f\xd1\x96\x03\x30\x50\x8b", + "QRG", + 18, + ), # eth / QRG + ( + 1, + b"\x69\x7b\xea\xc2\x8b\x09\xe1\x22\xc4\x33\x2d\x16\x39\x85\xe8\xa7\x31\x21\xb9\x7f", + "QRL", + 8, + ), # eth / QRL + ( + 1, + b"\x99\xea\x4d\xb9\xee\x77\xac\xd4\x0b\x11\x9b\xd1\xdc\x4e\x33\xe1\xc0\x70\xb8\x0d", + "QSP", + 18, + ), # eth / Quantstamp Token + ( + 1, + b"\x2c\x3c\x1f\x05\x18\x7d\xba\x7a\x5f\x2d\xd4\x7d\xca\x57\x28\x1c\x4d\x4f\x18\x3f", + "QTQ", + 18, + ), # eth / TiiQu's Q Token + ( + 1, + b"\x9a\x64\x2d\x6b\x33\x68\xdd\xc6\x62\xca\x24\x4b\xad\xf3\x2c\xda\x71\x60\x05\xbc", + "QTUM", + 18, + ), # eth / Qtum + ( + 1, + b"\x45\xed\xb5\x35\x94\x2a\x8c\x84\xd9\xf4\xb5\xd3\x7e\x1b\x25\xf9\x1e\xa4\x80\x4c", + "RAO", + 18, + ), # eth / RadioYo + ( + 1, + b"\xfc\x2c\x4d\x8f\x95\x00\x2c\x14\xed\x0a\x7a\xa6\x51\x02\xca\xc9\xe5\x95\x3b\x5e", + "RBLX", + 18, + ), # eth / Rublix + ( + 1, + b"\xf9\x70\xb8\xe3\x6e\x23\xf7\xfc\x3f\xd7\x52\xee\xa8\x6f\x8b\xe8\xd8\x33\x75\xa6", + "RCN", + 18, + ), # eth / Ripio Credit Network + ( + 1, + b"\x2a\x3a\xa9\xec\xa4\x1e\x72\x0e\xd4\x6b\x5a\x70\xd6\xc3\x7e\xfa\x47\xf7\x68\xac", + "RCT", + 18, + ), # eth / RCT + ( + 1, + b"\x25\x5a\xa6\xdf\x07\x54\x0c\xb5\xd3\xd2\x97\xf0\xd0\xd4\xd8\x4c\xb5\x2b\xc8\xe6", + "RDN", + 18, + ), # eth / Raiden Network + ( + 1, + b"\x76\x7b\xa2\x91\x5e\xc3\x44\x01\x5a\x79\x38\xe3\xee\xdf\xec\x27\x85\x19\x5d\x05", + "REA", + 18, + ), # eth / Realisto + ( + 1, + b"\x5f\x53\xf7\xa8\x07\x56\x14\xb6\x99\xba\xad\x0b\xc2\xc8\x99\xf4\xba\xd8\xfb\xbf", + "REBL", + 18, + ), # eth / Rebellious + ( + 1, + b"\x76\x96\x0d\xcc\xd5\xa1\xfe\x79\x9f\x7c\x29\xbe\x9f\x19\xce\xb4\x62\x7a\xeb\x2f", + "RED", + 18, + ), # eth / Red Community Token + ( + 1, + b"\x40\x8e\x41\x87\x6c\xcc\xdc\x0f\x92\x21\x06\x00\xef\x50\x37\x26\x56\x05\x2a\x38", + "REN", + 18, + ), # eth / Republic Token + ( + 1, + b"\xe9\x43\x27\xd0\x7f\xc1\x79\x07\xb4\xdb\x78\x8e\x5a\xdf\x2e\xd4\x24\xad\xdf\xf6", + "REP", + 18, + ), # eth / Augur + ( + 1, + b"\x8f\x82\x21\xaf\xbb\x33\x99\x8d\x85\x84\xa2\xb0\x57\x49\xba\x73\xc3\x7a\x93\x8a", + "REQ", + 18, + ), # eth / Request Network + ( + 1, + b"\xf0\x5a\x93\x82\xa4\xc3\xf2\x9e\x27\x84\x50\x27\x54\x29\x3d\x88\xb8\x35\x10\x9c", + "REX", + 18, + ), # eth / REX + ( + 1, + b"\xd0\x92\x9d\x41\x19\x54\xc4\x74\x38\xdc\x1d\x87\x1d\xd6\x08\x1f\x5c\x5e\x14\x9c", + "RFR", + 4, + ), # eth / Refereum + ( + 1, + b"\xdd\x00\x72\x78\xb6\x67\xf6\xbe\xf5\x2f\xd0\xa4\xc2\x36\x04\xaa\x1f\x96\x03\x9a", + "RIPT", + 8, + ), # eth / RiptideCoin + ( + 1, + b"\x60\x7f\x4c\x5b\xb6\x72\x23\x0e\x86\x72\x08\x55\x32\xf7\xe9\x01\x54\x4a\x73\x75", + "RLC", + 9, + ), # eth / IEx.ec + ( + 1, + b"\xcc\xed\x5b\x82\x88\x08\x6b\xe8\xc3\x8e\x23\x56\x7e\x68\x4c\x37\x40\xbe\x4d\x48", + "RLT", + 10, + ), # eth / RLT + ( + 1, + b"\xbe\x99\xb0\x97\x09\xfc\x75\x3b\x09\xbc\xf5\x57\xa9\x92\xf6\x60\x5d\x59\x97\xb0", + "RLTY", + 8, + ), # eth / SMARTRealty + ( + 1, + b"\x4a\x42\xd2\xc5\x80\xf8\x3d\xce\x40\x4a\xca\xd1\x8d\xab\x26\xdb\x11\xa1\x75\x0e", + "RLX", + 18, + ), # eth / Relex + ( + 1, + b"\x09\x96\xbf\xb5\xd0\x57\xfa\xa2\x37\x64\x0e\x25\x06\xbe\x7b\x4f\x9c\x46\xde\x0b", + "RNDR", + 18, + ), # eth / Render Token + ( + 1, + b"\xa4\x01\x06\x13\x4c\x5b\xf4\xc4\x14\x11\x55\x4e\x6d\xb9\x9b\x95\xa1\x5e\xd9\xd8", + "ROCK", + 18, + ), # eth / Rocket Token + ( + 1, + b"\xc9\xde\x4b\x7f\x0c\x3d\x99\x1e\x96\x71\x58\xe4\xd4\xbf\xa4\xb5\x1e\xc0\xb1\x14", + "ROK", + 18, + ), # eth / Rocketchain + ( + 1, + b"\x49\x93\xcb\x95\xc7\x44\x3b\xdc\x06\x15\x5c\x5f\x56\x88\xbe\x9d\x8f\x69\x99\xa5", + "ROUND", + 18, + ), # eth / ROUND + ( + 1, + b"\xb4\xef\xd8\x5c\x19\x99\x9d\x84\x25\x13\x04\xbd\xa9\x9e\x90\xb9\x23\x00\xbd\x93", + "RPL", + 18, + ), # eth / Rocket Pool + ( + 1, + b"\x54\xb2\x93\x22\x60\x00\xcc\xbf\xc0\x4d\xf9\x02\xee\xc5\x67\xcb\x4c\x35\xa9\x03", + "RTN", + 18, + ), # eth / RiderToken + ( + 1, + b"\x41\xf6\x15\xe2\x4f\xab\xd2\xb0\x97\xa3\x20\xe9\xe6\xc1\xf4\x48\xcb\x40\x52\x1c", + "RVL", + 18, + ), # eth / RVL + ( + 1, + b"\x3d\x1b\xa9\xbe\x9f\x66\xb8\xee\x10\x19\x11\xbc\x36\xd3\xfb\x56\x2e\xac\x22\x44", + "RVT", + 18, + ), # eth / Rivetz + ( + 1, + b"\x1e\xc8\xfe\x51\xa9\xb6\xa3\xa6\xc4\x27\xd1\x7d\x9e\xcc\x30\x60\xfb\xc4\xa4\x5c", + "S-A-PAT", + 18, + ), # eth / S-A-PAT + ( + 1, + b"\x3e\xb9\x1d\x23\x7e\x49\x1e\x0d\xee\x85\x82\xc4\x02\xd8\x5c\xb4\x40\xfb\x6b\x54", + "S-ETH", + 18, + ), # eth / S-ETH + ( + 1, + b"\x41\x56\xd3\x34\x2d\x5c\x38\x5a\x87\xd2\x64\xf9\x06\x53\x73\x35\x92\x00\x05\x81", + "SALT", + 8, + ), # eth / Salt Lending Token + ( + 1, + b"\x7c\x5a\x0c\xe9\x26\x7e\xd1\x9b\x22\xf8\xca\xe6\x53\xf1\x98\xe3\xe8\xda\xf0\x98", + "SAN", + 18, + ), # eth / Santiment + ( + 1, + b"\x78\xfe\x18\xe4\x1f\x43\x6e\x19\x81\xa3\xa6\x0d\x15\x57\xc8\xa7\xa9\x37\x04\x61", + "SCANDI", + 2, + ), # eth / Scandiweb Coin + ( + 1, + b"\xd7\x63\x17\x87\xb4\xdc\xc8\x7b\x12\x54\xcf\xd1\xe5\xce\x48\xe9\x68\x23\xde\xe8", + "SCL", + 8, + ), # eth / SocialCoin + ( + 1, + b"\x4c\xa7\x41\x85\x53\x2d\xc1\x78\x95\x27\x19\x4e\x5b\x9c\x86\x6d\xd3\x3f\x4e\x82", + "SenSatorI", + 18, + ), # eth / SenSatorI Token + ( + 1, + b"\x67\x45\xfa\xb6\x80\x1e\x37\x6c\xd2\x4f\x03\x57\x2b\x9c\x9b\x0d\x4e\xdd\xdc\xcf", + "SENSE", + 8, + ), # eth / Sensay + ( + 1, + b"\xe0\x6e\xda\x74\x35\xba\x74\x9b\x04\x73\x80\xce\xd4\x91\x21\xdd\xe9\x33\x34\xae", + "SET", + 0, + ), # eth / SET + ( + 1, + b"\x98\xf5\xe9\xb7\xf0\xe3\x39\x56\xc0\x44\x3e\x81\xbf\x7d\xeb\x8b\x5b\x1e\xd5\x45", + "SEXY", + 18, + ), # eth / Sexy Token + ( + 1, + b"\xa1\xcc\xc1\x66\xfa\xf0\xe9\x98\xb3\xe3\x32\x25\xa1\xa0\x30\x1b\x1c\x86\x11\x9d", + "SGEL", + 18, + ), # eth / SGELDER + ( + 1, + b"\x37\x42\x75\x76\x32\x4f\xe1\xf3\x62\x5c\x91\x02\x67\x47\x72\xd7\xcf\x71\x37\x7d", + "SGT", + 18, + ), # eth / SelfieYo Gold Token + ( + 1, + b"\xd2\x48\xb0\xd4\x8e\x44\xaa\xf9\xc4\x9a\xea\x03\x12\xbe\x7e\x13\xa6\xdc\x14\x68", + "SGT", + 1, + ), # eth / SGT + ( + 1, + b"\xef\x2e\x99\x66\xeb\x61\xbb\x49\x4e\x53\x75\xd5\xdf\x8d\x67\xb7\xdb\x8a\x78\x0d", + "SHIT", + 0, + ), # eth / SHIT + ( + 1, + b"\x8a\x18\x7d\x52\x85\xd3\x16\xbc\xbc\x9a\xda\xfc\x08\xb5\x1d\x70\xa0\xd8\xe0\x00", + "SIFT", + 0, + ), # eth / SIFT + ( + 1, + b"\x68\x88\xa1\x6e\xa9\x79\x2c\x15\xa4\xdc\xf2\xf6\xc6\x23\xd0\x55\xc8\xed\xe7\x92", + "SIG", + 18, + ), # eth / Signal + ( + 1, + b"\x2b\xdc\x0d\x42\x99\x60\x17\xfc\xe2\x14\xb2\x16\x07\xa5\x15\xda\x41\xa9\xe0\xc5", + "SKIN", + 6, + ), # eth / SKIN + ( + 1, + b"\x49\x94\xe8\x18\x97\xa9\x20\xc0\xfe\xa2\x35\xeb\x8c\xed\xee\xd3\xc6\xff\xf6\x97", + "SKO1", + 18, + ), # eth / Sikoba + ( + 1, + b"\x4c\x38\x2f\x8e\x09\x61\x5a\xc8\x6e\x08\xce\x58\x26\x6c\xc2\x27\xe7\xd4\xd9\x13", + "SKR", + 6, + ), # eth / SKR Token + ( + 1, + b"\x32\x4a\x48\xeb\xcb\xb4\x6e\x61\x99\x39\x31\xef\x9d\x35\xf6\x69\x7c\xd2\x90\x1b", + "SKRP", + 18, + ), # eth / Skraps + ( + 1, + b"\x6e\x34\xd8\xd8\x47\x64\xd4\x0f\x6d\x7b\x39\xcd\x56\x9f\xd0\x17\xbf\x53\x17\x7d", + "SKRP", + 18, + ), # eth / Skraps + ( + 1, + b"\xfd\xfe\x8b\x7a\xb6\xcf\x1b\xd1\xe3\xd1\x45\x38\xef\x40\x68\x62\x96\xc4\x20\x52", + "SKRP", + 18, + ), # eth / Skraps + ( + 1, + b"\x7a\x5f\xf2\x95\xdc\x82\x39\xd5\xc2\x37\x4e\x4d\x89\x42\x02\xaa\xf0\x29\xca\xb6", + "SLT", + 3, + ), # eth / Smartlands + ( + 1, + b"\x6f\x6d\xeb\x5d\xb0\xc4\x99\x4a\x82\x83\xa0\x1d\x6c\xfe\xeb\x27\xfc\x3b\xbe\x9c", + "SMART", + 0, + ), # eth / Smart Billions + ( + 1, + b"\x2d\xcf\xaa\xc1\x1c\x9e\xeb\xd8\xc6\xc4\x21\x03\xfe\x9e\x2a\x6a\xd2\x37\xaf\x27", + "SMT", + 18, + ), # eth / Smart Node + ( + 1, + b"\x55\xf9\x39\x85\x43\x1f\xc9\x30\x40\x77\x68\x7a\x35\xa1\xba\x10\x3d\xc1\xe0\x81", + "SMT", + 18, + ), # eth / SmartMesh + ( + 1, + b"\x78\xeb\x8d\xc6\x41\x07\x7f\x04\x9f\x91\x06\x59\xb6\xd5\x80\xe8\x0d\xc4\xd2\x37", + "SMT", + 8, + ), # eth / Social Media Market + ( + 1, + b"\xf4\x13\x41\x46\xaf\x2d\x51\x1d\xd5\xea\x8c\xdb\x1c\x4a\xc8\x8c\x57\xd6\x04\x04", + "SNC", + 18, + ), # eth / SNC + ( + 1, + b"\xf3\x33\xb2\xac\xe9\x92\xac\x2b\xbd\x87\x98\xbf\x57\xbc\x65\xa0\x61\x84\xaf\xba", + "SND", + 0, + ), # eth / Sandcoin + ( + 1, + b"\xcf\xd6\xae\x8b\xf1\x3f\x42\xde\x14\x86\x73\x51\xea\xff\x7a\x8a\x3b\x9f\xbb\xe7", + "SNG", + 8, + ), # eth / SINERGIA + ( + 1, + b"\xae\xc2\xe8\x7e\x0a\x23\x52\x66\xd9\xc5\xad\xc9\xde\xb4\xb2\xe2\x9b\x54\xd0\x09", + "SNGLS", + 0, + ), # eth / SingularDTV + ( + 1, + b"\x44\xf5\x88\xae\xeb\x8c\x44\x47\x14\x39\xd1\x27\x0b\x36\x03\xc6\x6a\x92\x62\xf1", + "SNIP", + 18, + ), # eth / SNIP + ( + 1, + b"\x98\x3f\x6d\x60\xdb\x79\xea\x8c\xa4\xeb\x99\x68\xc6\xaf\xf8\xcf\xa0\x4b\x3c\x63", + "SNM", + 18, + ), # eth / SNM + ( + 1, + b"\xbd\xc5\xba\xc3\x9d\xbe\x13\x2b\x1e\x03\x0e\x89\x8a\xe3\x83\x00\x17\xd7\xd9\x69", + "SNOV", + 18, + ), # eth / SNOV + ( + 1, + b"\x74\x4d\x70\xfd\xbe\x2b\xa4\xcf\x95\x13\x16\x26\x61\x4a\x17\x63\xdf\x80\x5b\x9e", + "SNT", + 18, + ), # eth / Status Network Token + ( + 1, + b"\x1f\x54\x63\x8b\x77\x37\x19\x3f\xfd\x86\xc1\x9e\xc5\x19\x07\xa7\xc4\x17\x55\xd8", + "SOL", + 6, + ), # eth / Sola Token + ( + 1, + b"\x42\xd6\x62\x2d\xec\xe3\x94\xb5\x49\x99\xfb\xd7\x3d\x10\x81\x23\x80\x6f\x6a\x18", + "SPANK", + 18, + ), # eth / SpankChain + ( + 1, + b"\x58\xbf\x7d\xf5\x7d\x9d\xa7\x11\x3c\x4c\xcb\x49\xd8\x46\x3d\x49\x08\xc7\x35\xcb", + "SPARC", + 18, + ), # eth / SPARC + ( + 1, + b"\x24\xae\xf3\xbf\x1a\x47\x56\x15\x00\xf9\x43\x0d\x74\xed\x40\x97\xc4\x7f\x51\xf2", + "SPARTA", + 4, + ), # eth / SPARTA + ( + 1, + b"\x85\x08\x93\x89\xc1\x4b\xd9\xc7\x7f\xc2\xb8\xf0\xc3\xd1\xdc\x33\x63\xbf\x06\xef", + "SPF", + 18, + ), # eth / Sportify + ( + 1, + b"\x20\xf7\xa3\xdd\xf2\x44\xdc\x92\x99\x97\x5b\x4d\xa1\xc3\x9f\x8d\x5d\x75\xf0\x5a", + "SPN", + 6, + ), # eth / Sapien + ( + 1, + b"\x68\xd5\x7c\x9a\x1c\x35\xf6\x3e\x2c\x83\xee\x8e\x49\xa6\x4e\x9d\x70\x52\x8d\x25", + "SRN", + 18, + ), # eth / Sirin Labs + ( + 1, + b"\xb1\x5f\xe5\xa1\x23\xe6\x47\xba\x59\x4c\xea\x7a\x1e\x64\x86\x46\xf9\x5e\xb4\xaa", + "SS", + 18, + ), # eth / Sharder + ( + 1, + b"\xbb\xff\x86\x2d\x90\x6e\x34\x8e\x99\x46\xbf\xb2\x13\x2e\xcb\x15\x7d\xa3\xd4\xb4", + "SS", + 18, + ), # eth / Sharder + ( + 1, + b"\x6e\x20\x50\xcb\xfb\x3e\xd8\xa4\xd3\x9b\x64\xcc\x9f\x47\xe7\x11\xa0\x3a\x5a\x89", + "SSH", + 18, + ), # eth / StreamShares + ( + 1, + b"\x9a\x00\x5c\x9a\x89\xbd\x72\xa4\xbd\x27\x72\x1e\x7a\x09\xa3\xc1\x1d\x2b\x03\xc4", + "STAC", + 18, + ), # eth / Starter Coin + ( + 1, + b"\xf7\x0a\x64\x2b\xd3\x87\xf9\x43\x80\xff\xb9\x04\x51\xc2\xc8\x1d\x4e\xb8\x2c\xbc", + "STAR", + 18, + ), # eth / Star Token + ( + 1, + b"\x62\x9a\xee\x55\xed\x49\x58\x1c\x33\xab\x27\xf9\x40\x3f\x79\x92\xa2\x89\xff\xd5", + "STC", + 18, + ), # eth / StrikeCoin Token + ( + 1, + b"\xae\x73\xb3\x8d\x1c\x9a\x8b\x27\x41\x27\xec\x30\x16\x0a\x49\x27\xc4\xd7\x18\x24", + "STK", + 18, + ), # eth / STK Token + ( + 1, + b"\x59\x93\x46\x77\x9e\x90\xfc\x3f\x5f\x99\x7b\x5e\xa7\x15\x34\x98\x20\xf9\x15\x71", + "STN", + 4, + ), # eth / Saturn Network + ( + 1, + b"\xb6\x4e\xf5\x1c\x88\x89\x72\xc9\x08\xcf\xac\xf5\x9b\x47\xc1\xaf\xbc\x0a\xb8\xac", + "STORJ", + 8, + ), # eth / STORJ + ( + 1, + b"\xd0\xa4\xb8\x94\x6c\xb5\x2f\x06\x61\x27\x3b\xfb\xc6\xfd\x0e\x0c\x75\xfc\x64\x33", + "STORM", + 18, + ), # eth / Storm Token + ( + 1, + b"\xec\xd5\x70\xbb\xf7\x47\x61\xb9\x60\xfa\x04\xcc\x10\xfe\x2c\x4e\x86\xff\xda\x36", + "STP", + 8, + ), # eth / StashPay + ( + 1, + b"\x5c\x3a\x22\x85\x10\xd2\x46\xb7\x8a\x37\x65\xc2\x02\x21\xcb\xf3\x08\x2b\x44\xa4", + "STQ", + 18, + ), # eth / Storiqa + ( + 1, + b"\x46\x49\x24\x73\x75\x5e\x8d\xf9\x60\xf8\x03\x48\x77\xf6\x17\x32\xd7\x18\xce\x96", + "STRC", + 8, + ), # eth / STRC + ( + 1, + b"\x00\x6b\xea\x43\xba\xa3\xf7\xa6\xf7\x65\xf1\x4f\x10\xa1\xa1\xb0\x83\x34\xef\x45", + "STX", + 18, + ), # eth / StoxToken + ( + 1, + b"\x12\x48\x0e\x24\xeb\x5b\xec\x1a\x9d\x43\x69\xca\xb6\xa8\x0c\xad\x3c\x0a\x37\x7a", + "SUB", + 2, + ), # eth / Substratum + ( + 1, + b"\x9e\x88\x61\x34\x18\xcf\x03\xdc\xa5\x4d\x6a\x2c\xf6\xad\x93\x4a\x78\xc7\xa1\x7a", + "SWM", + 18, + ), # eth / Swarm Fund Token + ( + 1, + b"\xb9\xe7\xf8\x56\x8e\x08\xd5\x65\x9f\x5d\x29\xc4\x99\x71\x73\xd8\x4c\xdf\x26\x07", + "SWT", + 18, + ), # eth / Swarm City Token + ( + 1, + b"\x12\xb3\x06\xfa\x98\xf4\xcb\xb8\xd4\x45\x7f\xdf\xf3\xa0\xa0\xa5\x6f\x07\xcc\xdf", + "SXDT", + 18, + ), # eth / Spectre.ai D-Token + ( + 1, + b"\x2c\x82\xc7\x3d\x5b\x34\xaa\x01\x59\x89\x46\x2b\x29\x48\xcd\x61\x6a\x37\x64\x1f", + "SXUT", + 18, + ), # eth / Spectre.ai U-Token + ( + 1, + b"\x10\xb1\x23\xfd\xdd\xe0\x03\x24\x31\x99\xaa\xd0\x35\x22\x06\x5d\xc0\x58\x27\xa0", + "SYN", + 18, + ), # eth / Synapse + ( + 1, + b"\xe7\x77\x5a\x6e\x9b\xcf\x90\x4e\xb3\x9d\xa2\xb6\x8c\x5e\xfb\x4f\x93\x60\xe0\x8c", + "TaaS", + 6, + ), # eth / Token-as-a-Service + ( + 1, + b"\xc2\x7a\x2f\x05\xfa\x57\x7a\x83\xba\x0f\xdb\x4c\x38\x44\x3c\x07\x18\x35\x65\x01", + "TAU", + 18, + ), # eth / Lamden Tau + ( + 1, + b"\xfa\xcc\xd5\xfc\x83\xc3\xe4\xc3\xc1\xac\x1e\xf3\x5d\x15\xad\xf0\x6b\xcf\x20\x9c", + "TBC2", + 8, + ), # eth / TBC2 + ( + 1, + b"\xaf\xe6\x05\x11\x34\x1a\x37\x48\x8d\xe2\x5b\xef\x35\x19\x52\x56\x2e\x31\xfc\xc1", + "TBT", + 8, + ), # eth / TBitBot + ( + 1, + b"\x2a\x1d\xba\xbe\x65\xc5\x95\xb0\x02\x2e\x75\x20\x8c\x34\x01\x41\x39\xd5\xd3\x57", + "TDH", + 18, + ), # eth / TrustedHealth + ( + 1, + b"\x85\xe0\x76\x36\x1c\xc8\x13\xa9\x08\xff\x67\x2f\x9b\xad\x15\x41\x47\x44\x02\xb2", + "TEL", + 2, + ), # eth / Telcoin + ( + 1, + b"\xa7\xf9\x76\xc3\x60\xeb\xbe\xd4\x46\x5c\x28\x55\x68\x4d\x1a\xae\x52\x71\xef\xa9", + "TFL", + 8, + ), # eth / TrueFlip + ( + 1, + b"\x38\x83\xf5\xe1\x81\xfc\xca\xf8\x41\x0f\xa6\x1e\x12\xb5\x9b\xad\x96\x3f\xb6\x45", + "THETA", + 18, + ), # eth / Theta Token + ( + 1, + b"\xfe\x7b\x91\x5a\x0b\xaa\x0e\x79\xf8\x5c\x55\x53\x26\x65\x13\xf7\xc1\xc0\x3e\xd0", + "THUG", + 18, + ), # eth / THUG + ( + 1, + b"\x65\x31\xf1\x33\xe6\xde\xeb\xe7\xf2\xdc\xe5\xa0\x44\x1a\xa7\xef\x33\x0b\x4e\x53", + "TIME", + 8, + ), # eth / Chronobank + ( + 1, + b"\x80\xbc\x55\x12\x56\x1c\x7f\x85\xa3\xa9\x50\x8c\x7d\xf7\x90\x1b\x37\x0f\xa1\xdf", + "TIO", + 18, + ), # eth / TIO + ( + 1, + b"\xea\x1f\x34\x6f\xaf\x02\x3f\x97\x4e\xb5\xad\xaf\x08\x8b\xbc\xdf\x02\xd7\x61\xf4", + "TIX", + 18, + ), # eth / Blocktix + ( + 1, + b"\xaa\xaf\x91\xd9\xb9\x0d\xf8\x00\xdf\x4f\x55\xc2\x05\xfd\x69\x89\xc9\x77\xe7\x3a", + "TKN", + 8, + ), # eth / TokenCard + ( + 1, + b"\x08\xf5\xa9\x23\x5b\x08\x17\x3b\x75\x69\xf8\x36\x45\xd2\xc7\xfb\x55\xe8\xcc\xd8", + "TNT", + 8, + ), # eth / Tierion Network Token + ( + 1, + b"\xcb\x3f\x90\x2b\xf9\x76\x26\x39\x1b\xf8\xba\x87\x26\x4b\xbc\x3d\xc1\x34\x69\xbe", + "TRC", + 18, + ), # eth / The Real Coin + ( + 1, + b"\x56\x6f\xd7\x99\x9b\x1f\xc3\x98\x80\x22\xbd\x38\x50\x7a\x48\xf0\xbc\xf2\x2c\x77", + "TRCN", + 18, + ), # eth / The Real Coin + ( + 1, + b"\xcb\x94\xbe\x6f\x13\xa1\x18\x2e\x4a\x4b\x61\x40\xcb\x7b\xf2\x02\x5d\x28\xe4\x1b", + "TRST", + 6, + ), # eth / TRST + ( + 1, + b"\xf2\x30\xb7\x90\xe0\x53\x90\xfc\x82\x95\xf4\xd3\xf6\x03\x32\xc9\x3b\xed\x42\xe2", + "TRX", + 6, + ), # eth / Tron Lab Token + ( + 1, + b"\x2e\xf1\xab\x8a\x26\x18\x7c\x58\xbb\x8a\xae\xb1\x1b\x2f\xc6\xd2\x5c\x5c\x07\x16", + "TWN", + 18, + ), # eth / The World News + ( + 1, + b"\xfb\xd0\xd1\xc7\x7b\x50\x17\x96\xa3\x5d\x86\xcf\x91\xd6\x5d\x97\x78\xee\xe6\x95", + "TWNKL", + 3, + ), # eth / Twinkle + ( + 1, + b"\x24\x69\x27\x91\xbc\x44\x4c\x5c\xd0\xb8\x1e\x3c\xbc\xab\xa4\xb0\x4a\xcd\x1f\x3b", + "UKG", + 18, + ), # eth / UnikoinGold + ( + 1, + b"\x10\x5d\x97\xef\x2e\x72\x3f\x1c\xfb\x24\x51\x9b\xc6\xff\x15\xa6\xd0\x91\xa3\xf1", + "UMKA", + 4, + ), # eth / UMKA + ( + 1, + b"\x8e\x5a\xfc\x69\xf6\x22\x7a\x3a\xd7\x5e\xd3\x46\xc8\x72\x3b\xc6\x2c\xe9\x71\x23", + "UMKA", + 4, + ), # eth / UMKA + ( + 1, + b"\x89\x20\x5a\x3a\x3b\x2a\x69\xde\x6d\xbf\x7f\x01\xed\x13\xb2\x10\x8b\x2c\x43\xe7", + "Unicorn", + 0, + ), # eth / Unicorn + ( + 1, + b"\xd0\x1d\xb7\x3e\x04\x78\x55\xef\xb4\x14\xe6\x20\x20\x98\xc4\xbe\x4c\xd2\x42\x3b", + "UQC", + 18, + ), # eth / Uquid Coin + ( + 1, + b"\xd7\x60\xad\xdf\xb2\x4d\x9c\x01\xfe\x4b\xfe\xa7\x47\x5c\x5e\x36\x36\x68\x40\x58", + "USDM", + 2, + ), # eth / Mether (USDM) + ( + 1, + b"\xda\xc1\x7f\x95\x8d\x2e\xe5\x23\xa2\x20\x62\x06\x99\x45\x97\xc1\x3d\x83\x1e\xc7", + "USDT", + 6, + ), # eth / USD Tether (erc20) + ( + 1, + b"\x70\xa7\x28\x33\xd6\xbf\x7f\x50\x8c\x82\x24\xce\x59\xea\x1e\xf3\xd0\xea\x3a\x38", + "UTK", + 18, + ), # eth / UTK + ( + 1, + b"\x9e\x33\x19\x63\x6e\x21\x26\xe3\xc0\xbc\x9e\x31\x34\xae\xc5\xe1\x50\x8a\x46\xc7", + "UTN-P", + 18, + ), # eth / Universa + ( + 1, + b"\x35\x43\x63\x8e\xd4\xa9\x00\x6e\x48\x40\xb1\x05\x94\x42\x71\xbc\xea\x15\x60\x5d", + "UUU", + 18, + ), # eth / U Networks + ( + 1, + b"\x82\xbd\x52\x6b\xdb\x71\x8c\x6d\x4d\xd2\x29\x1e\xd0\x13\xa5\x18\x6c\xae\x2d\xca", + "VDOC", + 18, + ), # eth / Duty of Care Token + ( + 1, + b"\x34\x0d\x2b\xde\x5e\xb2\x8c\x1e\xed\x91\xb2\xf7\x90\x72\x3e\x3b\x16\x06\x13\xb7", + "VEE", + 18, + ), # eth / BLOCKv + ( + 1, + b"\xeb\xed\x4f\xf9\xfe\x34\x41\x3d\xb8\xfc\x82\x94\x55\x6b\xbd\x15\x28\xa4\xda\xca", + "VENUS", + 3, + ), # eth / VENUS + ( + 1, + b"\x8f\x34\x70\xa7\x38\x8c\x05\xee\x4e\x7a\xf3\xd0\x1d\x8c\x72\x2b\x0f\xf5\x23\x74", + "VERI", + 18, + ), # eth / Veritas + ( + 1, + b"\xd8\x50\x94\x2e\xf8\x81\x1f\x2a\x86\x66\x92\xa6\x23\x01\x1b\xde\x52\xa4\x62\xc1", + "VET", + 18, + ), # eth / Vechain + ( + 1, + b"\x2c\x97\x4b\x2d\x0b\xa1\x71\x6e\x64\x4c\x1f\xc5\x99\x82\xa8\x9d\xdd\x2f\xf7\x24", + "VIB", + 18, + ), # eth / VIB + ( + 1, + b"\x88\x24\x48\xf8\x3d\x90\xb2\xbf\x47\x7a\xf2\xea\x79\x32\x7f\xde\xa1\x33\x5d\x93", + "VIBEX", + 18, + ), # eth / VIBEX Exchange Token + ( + 1, + b"\xe8\xff\x5c\x9c\x75\xde\xb3\x46\xac\xac\x49\x3c\x46\x3c\x89\x50\xbe\x03\xdf\xba", + "VIBEX", + 18, + ), # eth / VIBEX + ( + 1, + b"\xf0\x3f\x8d\x65\xba\xfa\x59\x86\x11\xc3\x49\x51\x24\x09\x3c\x56\xe8\xf6\x38\xf0", + "VIEW", + 18, + ), # eth / Viewly + ( + 1, + b"\x23\xb7\x5b\xc7\xaa\xf2\x8e\x2d\x66\x28\xc3\xf4\x24\xb3\x88\x2f\x8f\x07\x2a\x3c", + "VIT", + 18, + ), # eth / Vice Industry Token + ( + 1, + b"\x51\x94\x75\xb3\x16\x53\xe4\x6d\x20\xcd\x09\xf9\xfd\xcf\x3b\x12\xbd\xac\xb4\xf5", + "VIU", + 18, + ), # eth / VIU + ( + 1, + b"\x92\x2a\xc4\x73\xa3\xcc\x24\x1f\xd3\xa0\x04\x9e\xd1\x45\x36\x45\x2d\x58\xd7\x3c", + "VLD", + 18, + ), # eth / VLD + ( + 1, + b"\xc3\xbc\x9e\xb7\x1f\x75\xec\x43\x9a\x6b\x6c\x8e\x8b\x74\x6f\xcf\x5b\x62\xf7\x03", + "VOC", + 18, + ), # eth / VORMACOIN + ( + 1, + b"\x83\xee\xa0\x0d\x83\x8f\x92\xde\xc4\xd1\x47\x56\x97\xb9\xf4\xd3\x53\x7b\x56\xe3", + "VOISE", + 8, + ), # eth / Voise + ( + 1, + b"\xed\xba\xf3\xc5\x10\x03\x02\xdc\xdd\xa5\x32\x69\x32\x2f\x37\x30\xb1\xf0\x41\x6d", + "VRS", + 5, + ), # eth / Veros + ( + 1, + b"\x5c\x54\x3e\x7a\xe0\xa1\x10\x4f\x78\x40\x6c\x34\x0e\x9c\x64\xfd\x9f\xce\x51\x70", + "VSL", + 18, + ), # eth / Vdice + ( + 1, + b"\x28\x6b\xda\x14\x13\xa2\xdf\x81\x73\x1d\x49\x30\xce\x2f\x86\x2a\x35\xa6\x09\xfe", + "WaBi", + 18, + ), # eth / WaBi + ( + 1, + b"\x39\xbb\x25\x9f\x66\xe1\xc5\x9d\x5a\xbe\xf8\x83\x75\x97\x9b\x4d\x20\xd9\x80\x22", + "WAX", + 8, + ), # eth / WAX + ( + 1, + b"\x74\x95\x1b\x67\x7d\xe3\x2d\x59\x6e\xe8\x51\xa2\x33\x33\x69\x26\xe6\xa2\xcd\x09", + "WBA", + 7, + ), # eth / WeBetCrypto + ( + 1, + b"\x8f\x93\x6f\xe0\xfa\xf0\x60\x4c\x9c\x0e\xf2\x40\x6b\xde\x0a\x65\x36\x55\x15\xd6", + "WCN", + 18, + ), # eth / WorldCoinNetwork + ( + 1, + b"\x6a\x0a\x97\xe4\x7d\x15\xaa\xd1\xd1\x32\xa1\xac\x79\xa4\x80\xe3\xf2\x07\x90\x63", + "WCT", + 18, + ), # eth / WePower + ( + 1, + b"\xc0\x2a\xaa\x39\xb2\x23\xfe\x8d\x0a\x0e\x5c\x4f\x27\xea\xd9\x08\x3c\x75\x6c\xc2", + "WETH", + 18, + ), # eth / WETH + ( + 1, + b"\xf4\xfe\x95\x60\x38\x81\xd0\xe0\x79\x54\xfd\x76\x05\xe0\xe9\xa9\x16\xe4\x2c\x44", + "WHEN", + 18, + ), # eth / WHEN Token + ( + 1, + b"\xe2\x00\x64\x18\x90\x77\x2f\xce\x8e\xe6\xed\xc5\x35\x4c\xce\xa3\x0a\xc9\x2f\x49", + "WHO", + 18, + ), # eth / WhoHas + ( + 1, + b"\xe9\x33\xc0\xcd\x97\x84\x41\x4d\x5f\x27\x8c\x11\x49\x04\xf5\xa8\x4b\x39\x69\x19", + "WHO", + 18, + ), # eth / WhoHas + ( + 1, + b"\x5e\x4a\xbe\x64\x19\x65\x0c\xa8\x39\xce\x5b\xb7\xdb\x42\x2b\x88\x1a\x60\x64\xbb", + "WiC", + 18, + ), # eth / Wi Coin + ( + 1, + b"\x62\xcd\x07\xd4\x14\xec\x50\xb6\x8c\x7e\xca\xa8\x63\xa2\x3d\x34\x4f\x2d\x06\x2f", + "WIC", + 0, + ), # eth / WickNote + ( + 1, + b"\xd3\xc0\x07\x72\xb2\x4d\x99\x7a\x81\x22\x49\xca\x63\x7a\x92\x1e\x81\x35\x77\x01", + "WILD", + 18, + ), # eth / WILD Token + ( + 1, + b"\x66\x70\x88\xb2\x12\xce\x3d\x06\xa1\xb5\x53\xa7\x22\x1e\x1f\xd1\x90\x00\xd9\xaf", + "WINGS", + 18, + ), # eth / WINGS + ( + 1, + b"\x72\x87\x81\xe7\x57\x35\xdc\x09\x62\xdf\x3a\x51\xd7\xef\x47\xe7\x98\xa7\x10\x7e", + "WOLK", + 18, + ), # eth / WOLK + ( + 1, + b"\xf6\xb5\x5a\xcb\xbc\x49\xf4\x52\x4a\xa4\x8d\x19\x28\x1a\x9a\x77\xc5\x4d\xe1\x0f", + "WOLK", + 18, + ), # eth / Wolk Token + ( + 1, + b"\xd1\x8e\x45\x4d\x84\x4e\xb0\x00\x9d\x32\xe0\x7a\x0c\xde\x89\xe1\x8d\x64\xcf\xb4", + "WORK", + 18, + ), # eth / workTOKEN + ( + 1, + b"\x62\x08\x72\x45\x08\x71\x25\xd3\xdb\x5b\x9a\x3d\x71\x3d\x78\xe7\xbb\xc3\x1e\x54", + "WPC", + 18, + ), # eth / WorldPeaceCoin + ( + 1, + b"\x4c\xf4\x88\x38\x7f\x03\x5f\xf0\x8c\x37\x15\x15\x56\x2c\xba\x71\x2f\x90\x15\xd4", + "WPR", + 18, + ), # eth / WePower Token + ( + 1, + b"\x71\xe8\xd7\x4f\xf1\xc9\x23\xe3\x69\xd0\xe7\x0d\xfb\x09\x86\x66\x29\xc4\xdd\x35", + "WRK", + 18, + ), # eth / WorkCoin + ( + 1, + b"\xb7\xcb\x1c\x96\xdb\x6b\x22\xb0\xd3\xd9\x53\x6e\x01\x08\xd0\x62\xbd\x48\x8f\x74", + "WTC", + 18, + ), # eth / Walton + ( + 1, + b"\xd8\x95\x0f\xde\xaa\x10\x30\x4b\x7a\x7f\xd0\x3a\x2f\xc6\x6b\xc3\x9f\x3c\x71\x1a", + "WYS", + 18, + ), # eth / wystoken + ( + 1, + b"\x05\x60\x17\xc5\x5a\xe7\xae\x32\xd1\x2a\xef\x7c\x67\x9d\xf8\x3a\x85\xca\x75\xff", + "WYV", + 18, + ), # eth / WyvernToken + ( + 1, + b"\x91\x0d\xfc\x18\xd6\xea\x3d\x6a\x71\x24\xa6\xf8\xb5\x45\x8f\x28\x10\x60\xfa\x4c", + "X8X", + 18, + ), # eth / X8X + ( + 1, + b"\x4d\xf8\x12\xf6\x06\x4d\xef\x1e\x5e\x02\x9f\x1c\xa8\x58\x77\x7c\xc9\x8d\x2d\x81", + "XAUR", + 8, + ), # eth / Xaurum + ( + 1, + b"\x28\xde\xe0\x1d\x53\xfe\xd0\xed\xf5\xf6\xe3\x10\xbf\x8e\xf9\x31\x15\x13\xae\x40", + "XBP", + 18, + ), # eth / BlitzPredict + ( + 1, + b"\x4d\x82\x9f\x8c\x92\xa6\x69\x1c\x56\x30\x0d\x02\x0c\x9e\x0d\xb9\x84\xcf\xe2\xba", + "XCC", + 18, + ), # eth / CoinCrowd + ( + 1, + b"\x16\xaf\x5b\xfb\x4a\xe7\xe4\x75\xb9\xad\xc3\xbf\x5c\xb2\xf1\xe6\xa5\x0d\x79\x40", + "XFS", + 8, + ), # eth / Fanship + ( + 1, + b"\xf6\xb6\xaa\x0e\xf0\xf5\xed\xc2\xc1\xc5\xd9\x25\x47\x7f\x97\xea\xf6\x63\x03\xe7", + "XGG", + 8, + ), # eth / Going Gems + ( + 1, + b"\x53\x3e\xf0\x98\x4b\x2f\xaa\x22\x7a\xcc\x62\x0c\x67\xcc\xe1\x2a\xa3\x9c\xd8\xcd", + "XGM", + 8, + ), # eth / XGM + ( + 1, + b"\x30\xf4\xa3\xe0\xab\x7a\x76\x73\x3d\x8b\x60\xb8\x9d\xd9\x3c\x3d\x0b\x4c\x9e\x2f", + "XGT", + 18, + ), # eth / XGT + ( + 1, + b"\xb1\x10\xec\x7b\x1d\xcb\x8f\xab\x8d\xed\xbf\x28\xf5\x3b\xc6\x3e\xa5\xbe\xdd\x84", + "XID", + 8, + ), # eth / XID + ( + 1, + b"\xbc\x86\x72\x7e\x77\x0d\xe6\x8b\x10\x60\xc9\x1f\x6b\xb6\x94\x5c\x73\xe1\x03\x88", + "XNK", + 18, + ), # eth / Ink Protocol + ( + 1, + b"\xab\x95\xe9\x15\xc1\x23\xfd\xed\x5b\xdf\xb6\x32\x5e\x35\xef\x55\x15\xf1\xea\x69", + "XNN", + 18, + ), # eth / XENON + ( + 1, + b"\x57\x2e\x6f\x31\x80\x56\xba\x0c\x5d\x47\xa4\x22\x65\x31\x13\x84\x3d\x25\x06\x91", + "XNT", + 0, + ), # eth / XNT + ( + 1, + b"\xb2\x47\x54\xbe\x79\x28\x15\x53\xdc\x1a\xdc\x16\x0d\xdf\x5c\xd9\xb7\x43\x61\xa4", + "XRL", + 9, + ), # eth / XRL + ( + 1, + b"\x0f\x51\x3f\xfb\x49\x26\xff\x82\xd7\xf6\x0a\x05\x06\x90\x47\xac\xa2\x95\xc4\x13", + "XSC", + 18, + ), # eth / XSC + ( + 1, + b"\x6f\x7a\x4b\xac\x33\x15\xb5\x08\x2f\x79\x31\x61\xa2\x2e\x26\x66\x6d\x22\x71\x7f", + "YEED", + 18, + ), # eth / YEED + ( + 1, + b"\x0f\x33\xbb\x20\xa2\x82\xa7\x64\x9c\x7b\x3a\xff\x64\x4f\x08\x4a\x93\x48\xe9\x33", + "YUPIE", + 18, + ), # eth / YUPIE + ( + 1, + b"\x67\x81\xa0\xf8\x4c\x7e\x9e\x84\x6d\xcb\x84\xa9\xa5\xbd\x49\x33\x30\x67\xb1\x04", + "ZAP", + 18, + ), # eth / ZAP + ( + 1, + b"\x7a\x41\xe0\x51\x7a\x5e\xca\x4f\xdb\xc7\xfb\xeb\xa4\xd4\xc4\x7b\x9f\xf6\xdc\x63", + "ZCS", + 18, + ), # eth / Zeusshield + ( + 1, + b"\x05\xf4\xa4\x2e\x25\x1f\x2d\x52\xb8\xed\x15\xe9\xfe\xda\xac\xfc\xef\x1f\xad\x27", + "ZIL", + 12, + ), # eth / Zilliqa + ( + 1, + b"\x55\x4f\xfc\x77\xf4\x25\x1a\x9f\xb3\xc0\xe3\x59\x0a\x6a\x20\x5f\x8d\x4e\x06\x7d", + "ZMN", + 18, + ), # eth / ZMINE + ( + 1, + b"\xe4\x1d\x24\x89\x57\x1d\x32\x21\x89\x24\x6d\xaf\xa5\xeb\xde\x1f\x46\x99\xf4\x98", + "ZRX", + 18, + ), # eth / 0x Project + ( + 1, + b"\xe3\x86\xb1\x39\xed\x37\x15\xca\x4b\x18\xfd\x52\x67\x1b\xdc\xea\x1c\xdf\xe4\xb1", + "ZST", + 8, + ), # eth / Zeus Exchange + ( + 42, + b"\x86\x67\x55\x92\x54\x24\x1d\xde\xd4\xd1\x13\x92\xf8\x68\xd7\x20\x92\x76\x53\x67", + "Aeternity", + 18, + ), # kov / Aeternity + ( + 42, + b"\x3c\x67\xf7\xd4\xde\xcf\x77\x95\x22\x5f\x51\xb5\x41\x34\xf8\x11\x37\x38\x5f\x83", + "GUP", + 3, + ), # kov / GUP + ( + 4, + b"\x39\x8a\x7a\x69\xf3\xc5\x91\x81\xa1\xff\xe3\x4b\xed\x11\xdc\xb5\xdf\x86\x3a\x8a", + "AETH", + 18, + ), # rin / AKASHA Tokens + ( + 4, + b"\xe2\x78\x26\xee\x77\x8b\x6f\x78\xa4\x9a\x68\x6d\xa7\xd6\x4f\x6e\x7b\x08\x4a\x4f", + "BHNT", + 0, + ), # rin / Berlin Hack&Tell winner token + ( + 4, + b"\x8b\x65\xd4\xb7\xee\x3f\xff\xa9\x86\xc5\x77\xf0\xf4\xb7\x0a\x21\xba\xe3\xdd\x54", + "CTGA", + 18, + ), # rin / Convenient To Go + ( + 4, + b"\x27\x5a\x5b\x34\x65\x99\xb5\x69\x17\xe7\xb1\xc9\xde\x01\x9d\xcf\x9e\xad\x86\x1a", + "KC", + 18, + ), # rin / Karma Token + ( + 4, + b"\x64\x75\xa7\xfa\x6e\xd2\xd5\x18\x0f\x0e\x0a\x07\xc2\xd9\x51\xd1\x2c\x0e\xdb\x91", + "NONE", + 0, + ), # rin / None + ( + 4, + b"\x12\xfe\x17\x4c\x09\x7f\x6b\x3e\x87\x6b\x3b\x06\x0c\x90\x61\xf4\xb9\xde\xbb\x80", + "PPD", + 18, + ), # rin / PP Donation + ( + 4, + b"\x0a\x05\x7a\x87\xce\x9c\x56\xd7\xe3\x36\xb4\x17\xc7\x9c\xf3\x0e\x8d\x27\x86\x0b", + "WALL", + 15, + ), # rin / WALLETH Community-Token + ( + 3, + b"\x6f\x95\xa3\xb6\x82\xf8\xe9\xaa\xcc\x86\xd0\x57\xa6\xdf\x88\xa0\xe6\x81\x45\xa8", + "ILSC", + 2, + ), # rop / IsraCoin + ( + 3, + b"\xfd\x5a\x69\xa1\x30\x95\x95\xff\x51\x21\x55\x3f\x52\xc8\xa5\xb2\xb1\xb3\x10\x31", + "NONE", + 0, + ), # rop / None + ( + 8, + b"\xff\x3b\xf0\x57\xad\xf3\xb0\xe0\x15\xb6\x46\x53\x31\xa6\x23\x6e\x55\x68\x82\x74", + "BEER", + 0, + ), # ubq / BEER + ( + 8, + b"\x08\x53\x3d\x6a\x06\xce\x36\x52\x98\xb1\x2e\xf9\x2e\xb4\x07\xcb\xa8\xaa\x82\x73", + "CEFS", + 8, + ), # ubq / CEFS + ( + 8, + b"\x94\xad\x7e\x41\xc1\xd4\x40\x22\xc4\xf4\x7c\xb1\xba\x01\x9f\xd1\xa0\x22\xc5\x36", + "DOT", + 8, + ), # ubq / DOT + ( + 8, + b"\x4b\x48\x99\xa1\x0f\x3e\x50\x7d\xb2\x07\xb0\xee\x24\x26\x02\x9e\xfa\x16\x8a\x67", + "QWARK", + 8, + ), # ubq / QWARK + ( + 8, + b"\x5e\x17\x15\xbb\x79\x80\x5b\xd6\x72\x72\x97\x60\xb3\xf7\xf3\x4d\x6f\x48\x50\x98", + "RICKS", + 8, + ), # ubq / RICKS ] diff --git a/src/apps/ethereum/verify_message.py b/src/apps/ethereum/verify_message.py index 806e23ebd..38cb128df 100644 --- a/src/apps/ethereum/verify_message.py +++ b/src/apps/ethereum/verify_message.py @@ -18,25 +18,25 @@ async def ethereum_verify_message(ctx, msg): pubkey = secp256k1.verify_recover(sig, digest) if not pubkey: - raise ValueError('Invalid signature') + raise ValueError("Invalid signature") pkh = sha3_256(pubkey[1:]).digest(True)[-20:] if msg.address != pkh: - raise ValueError('Invalid signature') + raise ValueError("Invalid signature") - address = '0x' + hexlify(msg.address).decode() + address = "0x" + hexlify(msg.address).decode() await require_confirm_verify_message(ctx, address, msg.message) - return Success(message='Message verified') + return Success(message="Message verified") async def require_confirm_verify_message(ctx, address, message): - text = Text('Confirm address') + text = Text("Confirm address") text.mono(*split_address(address)) await require_confirm(ctx, text) - text = Text('Verify message') + text = Text("Verify message") text.mono(*split_message(message)) await require_confirm(ctx, text) diff --git a/src/apps/fido_u2f/__init__.py b/src/apps/fido_u2f/__init__.py index 8b3ba780a..e481a2914 100644 --- a/src/apps/fido_u2f/__init__.py +++ b/src/apps/fido_u2f/__init__.py @@ -18,17 +18,17 @@ _TYPE_INIT = const(0x80) # initial frame identifier _TYPE_CONT = const(0x00) # continuation frame identifier # types of cmd -_CMD_PING = const(0x81) # echo data through local processor only -_CMD_MSG = const(0x83) # send U2F message frame -_CMD_LOCK = const(0x84) # send lock channel command -_CMD_INIT = const(0x86) # channel initialization -_CMD_WINK = const(0x88) # send device identification wink +_CMD_PING = const(0x81) # echo data through local processor only +_CMD_MSG = const(0x83) # send U2F message frame +_CMD_LOCK = const(0x84) # send lock channel command +_CMD_INIT = const(0x86) # channel initialization +_CMD_WINK = const(0x88) # send device identification wink _CMD_ERROR = const(0xbf) # error response # types for the msg cmd -_MSG_REGISTER = const(0x01) # registration command +_MSG_REGISTER = const(0x01) # registration command _MSG_AUTHENTICATE = const(0x02) # authenticate/sign command -_MSG_VERSION = const(0x03) # read version string command +_MSG_VERSION = const(0x03) # read version string command # hid error codes _ERR_NONE = const(0x00) # no error @@ -52,8 +52,8 @@ _SW_INS_NOT_SUPPORTED = const(0x6d00) _SW_CLA_NOT_SUPPORTED = const(0x6e00) # init response -_CAPFLAG_WINK = const(0x01) # device supports _CMD_WINK -_U2FHID_IF_VERSION = const(2) # interface version +_CAPFLAG_WINK = const(0x01) # device supports _CMD_WINK +_U2FHID_IF_VERSION = const(2) # interface version # register response _U2F_KEY_PATH = const(0x80553246) @@ -63,18 +63,18 @@ _U2F_ATT_CERT = b"0\x82\x01\x180\x81\xc0\x02\t\x00\xb1\xd9\x8fBdr\xd3,0\n\x06\x0 _BOGUS_APPID = b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" # authentication control byte -_AUTH_ENFORCE = const(0x03) # enforce user presence and sign +_AUTH_ENFORCE = const(0x03) # enforce user presence and sign _AUTH_CHECK_ONLY = const(0x07) # check only -_AUTH_FLAG_TUP = const(0x01) # test of user presence set +_AUTH_FLAG_TUP = const(0x01) # test of user presence set # common raw message format (ISO7816-4:2005 mapping) -_APDU_CLA = const(0) # uint8_t cla; // Class - reserved -_APDU_INS = const(1) # uint8_t ins; // U2F instruction -_APDU_P1 = const(2) # uint8_t p1; // U2F parameter 1 -_APDU_P2 = const(3) # uint8_t p2; // U2F parameter 2 -_APDU_LC1 = const(4) # uint8_t lc1; // Length field, set to zero -_APDU_LC2 = const(5) # uint8_t lc2; // Length field, MSB -_APDU_LC3 = const(6) # uint8_t lc3; // Length field, LSB +_APDU_CLA = const(0) # uint8_t cla; // Class - reserved +_APDU_INS = const(1) # uint8_t ins; // U2F instruction +_APDU_P1 = const(2) # uint8_t p1; // U2F parameter 1 +_APDU_P2 = const(3) # uint8_t p2; // U2F parameter 2 +_APDU_LC1 = const(4) # uint8_t lc1; // Length field, set to zero +_APDU_LC2 = const(5) # uint8_t lc2; // Length field, MSB +_APDU_LC3 = const(6) # uint8_t lc3; // Length field, LSB _APDU_DATA = const(7) # uint8_t data[1]; // Data field @@ -85,10 +85,10 @@ def frame_init() -> dict: # uint8_t bcntl; // Message byte count - low part # uint8_t data[HID_RPT_SIZE - 7]; // Data payload return { - 'cid': 0 | uctypes.UINT32, - 'cmd': 4 | uctypes.UINT8, - 'bcnt': 5 | uctypes.UINT16, - 'data': (7 | uctypes.ARRAY, (_HID_RPT_SIZE - 7) | uctypes.UINT8), + "cid": 0 | uctypes.UINT32, + "cmd": 4 | uctypes.UINT8, + "bcnt": 5 | uctypes.UINT16, + "data": (7 | uctypes.ARRAY, (_HID_RPT_SIZE - 7) | uctypes.UINT8), } @@ -97,9 +97,9 @@ def frame_cont() -> dict: # uint8_t seq; // Sequence number - b7 cleared # uint8_t data[HID_RPT_SIZE - 5]; // Data payload return { - 'cid': 0 | uctypes.UINT32, - 'seq': 4 | uctypes.UINT8, - 'data': (5 | uctypes.ARRAY, (_HID_RPT_SIZE - 5) | uctypes.UINT8), + "cid": 0 | uctypes.UINT32, + "seq": 4 | uctypes.UINT8, + "data": (5 | uctypes.ARRAY, (_HID_RPT_SIZE - 5) | uctypes.UINT8), } @@ -112,13 +112,13 @@ def resp_cmd_init() -> dict: # uint8_t versionBuild; // Build version number # uint8_t capFlags; // Capabilities flags return { - 'nonce': (0 | uctypes.ARRAY, 8 | uctypes.UINT8), - 'cid': 8 | uctypes.UINT32, - 'versionInterface': 12 | uctypes.UINT8, - 'versionMajor': 13 | uctypes.UINT8, - 'versionMinor': 14 | uctypes.UINT8, - 'versionBuild': 15 | uctypes.UINT8, - 'capFlags': 16 | uctypes.UINT8, + "nonce": (0 | uctypes.ARRAY, 8 | uctypes.UINT8), + "cid": 8 | uctypes.UINT32, + "versionInterface": 12 | uctypes.UINT8, + "versionMajor": 13 | uctypes.UINT8, + "versionMinor": 14 | uctypes.UINT8, + "versionBuild": 15 | uctypes.UINT8, + "capFlags": 16 | uctypes.UINT8, } @@ -134,13 +134,13 @@ def resp_cmd_register(khlen: int, certlen: int, siglen: int) -> dict: # uint8_t sig[siglen]; // Registration signature # uint16_t status; return { - 'registerId': 0 | uctypes.UINT8, - 'pubKey': (1 | uctypes.ARRAY, 65 | uctypes.UINT8), - 'keyHandleLen': 66 | uctypes.UINT8, - 'keyHandle': (67 | uctypes.ARRAY, khlen | uctypes.UINT8), - 'cert': (cert_ofs | uctypes.ARRAY, certlen | uctypes.UINT8), - 'sig': (sig_ofs | uctypes.ARRAY, siglen | uctypes.UINT8), - 'status': status_ofs | uctypes.UINT16, + "registerId": 0 | uctypes.UINT8, + "pubKey": (1 | uctypes.ARRAY, 65 | uctypes.UINT8), + "keyHandleLen": 66 | uctypes.UINT8, + "keyHandle": (67 | uctypes.ARRAY, khlen | uctypes.UINT8), + "cert": (cert_ofs | uctypes.ARRAY, certlen | uctypes.UINT8), + "sig": (sig_ofs | uctypes.ARRAY, siglen | uctypes.UINT8), + "status": status_ofs | uctypes.UINT16, } @@ -154,10 +154,10 @@ def req_cmd_authenticate(khlen: int) -> dict: # uint8_t keyHandleLen; // Length of key handle # uint8_t keyHandle[khlen]; // Key handle return { - 'chal': (0 | uctypes.ARRAY, 32 | uctypes.UINT8), - 'appId': (32 | uctypes.ARRAY, 32 | uctypes.UINT8), - 'keyHandleLen': 64 | uctypes.UINT8, - 'keyHandle': (65 | uctypes.ARRAY, khlen | uctypes.UINT8), + "chal": (0 | uctypes.ARRAY, 32 | uctypes.UINT8), + "appId": (32 | uctypes.ARRAY, 32 | uctypes.UINT8), + "keyHandleLen": 64 | uctypes.UINT8, + "keyHandle": (65 | uctypes.ARRAY, khlen | uctypes.UINT8), } @@ -168,17 +168,17 @@ def resp_cmd_authenticate(siglen: int) -> dict: # uint8_t sig[siglen]; // Signature # uint16_t status; return { - 'flags': 0 | uctypes.UINT8, - 'ctr': 1 | uctypes.UINT32, - 'sig': (5 | uctypes.ARRAY, siglen | uctypes.UINT8), - 'status': status_ofs | uctypes.UINT16, + "flags": 0 | uctypes.UINT8, + "ctr": 1 | uctypes.UINT32, + "sig": (5 | uctypes.ARRAY, siglen | uctypes.UINT8), + "status": status_ofs | uctypes.UINT16, } def overlay_struct(buf, desc): desc_size = uctypes.sizeof(desc, uctypes.BIG_ENDIAN) if desc_size > len(buf): - raise ValueError('desc is too big (%d > %d)' % (desc_size, len(buf))) + raise ValueError("desc is too big (%d > %d)" % (desc_size, len(buf))) return uctypes.struct(uctypes.addressof(buf), desc, uctypes.BIG_ENDIAN) @@ -189,8 +189,9 @@ def make_struct(desc): class Msg: - - def __init__(self, cid: int, cla: int, ins: int, p1: int, p2: int, lc: int, data: bytes) -> None: + def __init__( + self, cid: int, cla: int, ins: int, p1: int, p2: int, lc: int, data: bytes + ) -> None: self.cid = cid self.cla = cla self.ins = ins @@ -201,7 +202,6 @@ class Msg: class Cmd: - def __init__(self, cid: int, cmd: int, data: bytes) -> None: self.cid = cid self.cmd = cmd @@ -212,10 +212,12 @@ class Cmd: ins = self.data[_APDU_INS] p1 = self.data[_APDU_P1] p2 = self.data[_APDU_P2] - lc = (self.data[_APDU_LC1] << 16) + \ - (self.data[_APDU_LC2] << 8) + \ - (self.data[_APDU_LC3]) - data = self.data[_APDU_DATA:_APDU_DATA + lc] + lc = ( + (self.data[_APDU_LC1] << 16) + + (self.data[_APDU_LC2] << 8) + + (self.data[_APDU_LC3]) + ) + data = self.data[_APDU_DATA : _APDU_DATA + lc] return Msg(self.cid, cla, ins, p1, p2, lc, data) @@ -235,7 +237,7 @@ async def read_cmd(iface: io.HID) -> Cmd: if ifrm.cmd & _TYPE_MASK == _TYPE_CONT: # unexpected cont packet, abort current msg if __debug__: - log.warning(__name__, '_TYPE_CONT') + log.warning(__name__, "_TYPE_CONT") return None if datalen < bcnt: @@ -253,13 +255,13 @@ async def read_cmd(iface: io.HID) -> Cmd: if cfrm.seq == _CMD_INIT: # _CMD_INIT frame, cancels current channel ifrm = overlay_struct(buf, desc_init) - data = ifrm.data[:ifrm.bcnt] + data = ifrm.data[: ifrm.bcnt] break if cfrm.cid != ifrm.cid: # cont frame for a different channel, reply with BUSY and skip if __debug__: - log.warning(__name__, '_ERR_CHANNEL_BUSY') + log.warning(__name__, "_ERR_CHANNEL_BUSY") await send_cmd(cmd_error(cfrm.cid, _ERR_CHANNEL_BUSY), iface) continue @@ -267,7 +269,7 @@ async def read_cmd(iface: io.HID) -> Cmd: # cont frame for this channel, but incorrect seq number, abort # current msg if __debug__: - log.warning(__name__, '_ERR_INVALID_SEQ') + log.warning(__name__, "_ERR_INVALID_SEQ") await send_cmd(cmd_error(cfrm.cid, _ERR_INVALID_SEQ), iface) return None @@ -330,7 +332,6 @@ _CONFIRM_TIMEOUT_MS = const(10 * 1000) class ConfirmState: - def __init__(self) -> None: self.reset() @@ -382,19 +383,20 @@ class ConfirmState: from trezor.ui.text import Text if bytes(self.app_id) == _BOGUS_APPID: - text = Text('U2F mismatch', ui.ICON_WRONG, icon_color=ui.RED) - text.normal('Another U2F device', 'was used to register', 'in this application.') + text = Text("U2F mismatch", ui.ICON_WRONG, icon_color=ui.RED) + text.normal( + "Another U2F device", "was used to register", "in this application." + ) text.render() await loop.sleep(3 * 1000 * 1000) self.confirmed = True else: content = ConfirmContent(self.action, self.app_id) - dialog = ConfirmDialog(content, ) + dialog = ConfirmDialog(content) self.confirmed = await dialog == CONFIRMED class ConfirmContent(ui.Widget): - def __init__(self, action: int, app_id: bytes) -> None: self.action = action self.app_id = app_id @@ -411,25 +413,30 @@ class ConfirmContent(ui.Widget): if app_id == _BOGUS_APPID: # TODO: display a warning dialog for bogus app ids - name = 'Another U2F device' - icon = res.load('apps/fido_u2f/res/u2f_generic.toif') # TODO: warning icon + name = "Another U2F device" + icon = res.load("apps/fido_u2f/res/u2f_generic.toif") # TODO: warning icon elif app_id in knownapps.knownapps: name = knownapps.knownapps[app_id] try: - icon = res.load('apps/fido_u2f/res/u2f_%s.toif' % name.lower().replace(' ', '_')) + icon = res.load( + "apps/fido_u2f/res/u2f_%s.toif" % name.lower().replace(" ", "_") + ) except Exception: - icon = res.load('apps/fido_u2f/res/u2f_generic.toif') + icon = res.load("apps/fido_u2f/res/u2f_generic.toif") else: - name = '%s...%s' % (hexlify(app_id[:4]).decode(), hexlify(app_id[-4:]).decode()) - icon = res.load('apps/fido_u2f/res/u2f_generic.toif') + name = "%s...%s" % ( + hexlify(app_id[:4]).decode(), + hexlify(app_id[-4:]).decode(), + ) + icon = res.load("apps/fido_u2f/res/u2f_generic.toif") self.app_name = name self.app_icon = icon def render(self) -> None: if self.action == _CONFIRM_REGISTER: - header = 'U2F Register' + header = "U2F Register" else: - header = 'U2F Authenticate' + header = "U2F Authenticate" ui.header(header, ui.ICON_DEFAULT, ui.GREEN, ui.BG, ui.GREEN) ui.display.image((ui.WIDTH - 64) // 2, 64, self.app_icon) ui.display.text_center(ui.WIDTH // 2, 168, self.app_name, ui.MONO, ui.FG, ui.BG) @@ -441,46 +448,46 @@ def dispatch_cmd(req: Cmd, state: ConfirmState) -> Cmd: if m.cla != 0: if __debug__: - log.warning(__name__, '_SW_CLA_NOT_SUPPORTED') + log.warning(__name__, "_SW_CLA_NOT_SUPPORTED") return msg_error(req.cid, _SW_CLA_NOT_SUPPORTED) if m.lc + _APDU_DATA > len(req.data): if __debug__: - log.warning(__name__, '_SW_WRONG_LENGTH') + log.warning(__name__, "_SW_WRONG_LENGTH") return msg_error(req.cid, _SW_WRONG_LENGTH) if m.ins == _MSG_REGISTER: if __debug__: - log.debug(__name__, '_MSG_REGISTER') + log.debug(__name__, "_MSG_REGISTER") return msg_register(m, state) elif m.ins == _MSG_AUTHENTICATE: if __debug__: - log.debug(__name__, '_MSG_AUTHENTICATE') + log.debug(__name__, "_MSG_AUTHENTICATE") return msg_authenticate(m, state) elif m.ins == _MSG_VERSION: if __debug__: - log.debug(__name__, '_MSG_VERSION') + log.debug(__name__, "_MSG_VERSION") return msg_version(m) else: if __debug__: - log.warning(__name__, '_SW_INS_NOT_SUPPORTED: %d', m.ins) + log.warning(__name__, "_SW_INS_NOT_SUPPORTED: %d", m.ins) return msg_error(req.cid, _SW_INS_NOT_SUPPORTED) elif req.cmd == _CMD_INIT: if __debug__: - log.debug(__name__, '_CMD_INIT') + log.debug(__name__, "_CMD_INIT") return cmd_init(req) elif req.cmd == _CMD_PING: if __debug__: - log.debug(__name__, '_CMD_PING') + log.debug(__name__, "_CMD_PING") return req elif req.cmd == _CMD_WINK: if __debug__: - log.debug(__name__, '_CMD_WINK') + log.debug(__name__, "_CMD_WINK") return req else: if __debug__: - log.warning(__name__, '_ERR_INVALID_CMD: %d', req.cmd) + log.warning(__name__, "_ERR_INVALID_CMD: %d", req.cmd) return cmd_error(req.cid, _ERR_INVALID_CMD) @@ -510,13 +517,13 @@ def msg_register(req: Msg, state: ConfirmState) -> Cmd: if not storage.is_initialized(): if __debug__: - log.warning(__name__, 'not initialized') + log.warning(__name__, "not initialized") return msg_error(req.cid, _SW_CONDITIONS_NOT_SATISFIED) # check length of input data if len(req.data) != 64: if __debug__: - log.warning(__name__, '_SW_WRONG_LENGTH req.data') + log.warning(__name__, "_SW_WRONG_LENGTH req.data") return msg_error(req.cid, _SW_WRONG_LENGTH) # parse challenge and app_id @@ -532,12 +539,12 @@ def msg_register(req: Msg, state: ConfirmState) -> Cmd: # wait for a button or continue if not state.confirmed: if __debug__: - log.info(__name__, 'waiting for button') + log.info(__name__, "waiting for button") return msg_error(req.cid, _SW_CONDITIONS_NOT_SATISFIED) # sign the registration challenge and return if __debug__: - log.info(__name__, 'signing register') + log.info(__name__, "signing register") buf = msg_register_sign(chal, app_id) state.reset() @@ -554,11 +561,11 @@ def msg_register_sign(challenge: bytes, app_id: bytes) -> bytes: nodepath = [_U2F_KEY_PATH] + keypath # prepare signing key from random path, compute decompressed public key - node = seed.derive_node_without_passphrase(nodepath, 'nist256p1') + node = seed.derive_node_without_passphrase(nodepath, "nist256p1") pubkey = nist256p1.publickey(node.private_key(), False) # first half of keyhandle is keypath - keybuf = ustruct.pack('>8L', *keypath) + keybuf = ustruct.pack(">8L", *keypath) # second half of keyhandle is a hmac of app_id and keypath keybase = hmac.Hmac(node.private_key(), app_id, hashlib.sha256) @@ -567,12 +574,12 @@ def msg_register_sign(challenge: bytes, app_id: bytes) -> bytes: # hash the request data together with keyhandle and pubkey dig = hashlib.sha256() - dig.update(b'\x00') # uint8_t reserved; - dig.update(app_id) # uint8_t appId[32]; + dig.update(b"\x00") # uint8_t reserved; + dig.update(app_id) # uint8_t appId[32]; dig.update(challenge) # uint8_t chal[32]; - dig.update(keybuf) # uint8_t keyHandle[64]; + dig.update(keybuf) # uint8_t keyHandle[64]; dig.update(keybase) - dig.update(pubkey) # uint8_t pubKey[65]; + dig.update(pubkey) # uint8_t pubKey[65]; dig = dig.digest() # sign the digest and convert to der @@ -580,8 +587,9 @@ def msg_register_sign(challenge: bytes, app_id: bytes) -> bytes: sig = der.encode_seq((sig[1:33], sig[33:])) # pack to a response - buf, resp = make_struct(resp_cmd_register( - len(keybuf) + len(keybase), len(_U2F_ATT_CERT), len(sig))) + buf, resp = make_struct( + resp_cmd_register(len(keybuf) + len(keybase), len(_U2F_ATT_CERT), len(sig)) + ) resp.registerId = _U2F_REGISTER_ID utils.memcpy(resp.pubKey, 0, pubkey, 0, len(pubkey)) resp.keyHandleLen = len(keybuf) + len(keybase) @@ -599,20 +607,20 @@ def msg_authenticate(req: Msg, state: ConfirmState) -> Cmd: if not storage.is_initialized(): if __debug__: - log.warning(__name__, 'not initialized') + log.warning(__name__, "not initialized") return msg_error(req.cid, _SW_CONDITIONS_NOT_SATISFIED) # we need at least keyHandleLen if len(req.data) <= _REQ_CMD_AUTHENTICATE_KHLEN: if __debug__: - log.warning(__name__, '_SW_WRONG_LENGTH req.data') + log.warning(__name__, "_SW_WRONG_LENGTH req.data") return msg_error(req.cid, _SW_WRONG_LENGTH) # check keyHandleLen khlen = req.data[_REQ_CMD_AUTHENTICATE_KHLEN] if khlen != 64: if __debug__: - log.warning(__name__, '_SW_WRONG_LENGTH khlen') + log.warning(__name__, "_SW_WRONG_LENGTH khlen") return msg_error(req.cid, _SW_WRONG_LENGTH) auth = overlay_struct(req.data, req_cmd_authenticate(khlen)) @@ -626,13 +634,13 @@ def msg_authenticate(req: Msg, state: ConfirmState) -> Cmd: # if _AUTH_CHECK_ONLY is requested, return, because keyhandle has been checked already if req.p1 == _AUTH_CHECK_ONLY: if __debug__: - log.info(__name__, '_AUTH_CHECK_ONLY') + log.info(__name__, "_AUTH_CHECK_ONLY") return msg_error(req.cid, _SW_CONDITIONS_NOT_SATISFIED) # from now on, only _AUTH_ENFORCE is supported if req.p1 != _AUTH_ENFORCE: if __debug__: - log.info(__name__, '_AUTH_ENFORCE') + log.info(__name__, "_AUTH_ENFORCE") return msg_error(req.cid, _SW_WRONG_DATA) # check equality with last request @@ -644,12 +652,12 @@ def msg_authenticate(req: Msg, state: ConfirmState) -> Cmd: # wait for a button or continue if not state.confirmed: if __debug__: - log.info(__name__, 'waiting for button') + log.info(__name__, "waiting for button") return msg_error(req.cid, _SW_CONDITIONS_NOT_SATISFIED) # sign the authentication challenge and return if __debug__: - log.info(__name__, 'signing authentication') + log.info(__name__, "signing authentication") buf = msg_authenticate_sign(auth.chal, auth.appId, node.private_key()) state.reset() @@ -662,18 +670,18 @@ def msg_authenticate_genkey(app_id: bytes, keyhandle: bytes): # unpack the keypath from the first half of keyhandle keybuf = keyhandle[:32] - keypath = ustruct.unpack('>8L', keybuf) + keypath = ustruct.unpack(">8L", keybuf) # check high bit for hardened keys for i in keypath: if not i & HARDENED: if __debug__: - log.warning(__name__, 'invalid key path') + log.warning(__name__, "invalid key path") return None # derive the signing key nodepath = [_U2F_KEY_PATH] + list(keypath) - node = seed.derive_node_without_passphrase(nodepath, 'nist256p1') + node = seed.derive_node_without_passphrase(nodepath, "nist256p1") # second half of keyhandle is a hmac of app_id and keypath keybase = hmac.Hmac(node.private_key(), app_id, hashlib.sha256) @@ -683,7 +691,7 @@ def msg_authenticate_genkey(app_id: bytes, keyhandle: bytes): # verify the hmac if keybase != keyhandle[32:]: if __debug__: - log.warning(__name__, 'invalid key handle') + log.warning(__name__, "invalid key handle") return None return node @@ -694,13 +702,13 @@ def msg_authenticate_sign(challenge: bytes, app_id: bytes, privkey: bytes) -> by # get next counter ctr = storage.next_u2f_counter() - ctrbuf = ustruct.pack('>L', ctr) + ctrbuf = ustruct.pack(">L", ctr) # hash input data together with counter dig = hashlib.sha256() - dig.update(app_id) # uint8_t appId[32]; - dig.update(flags) # uint8_t flags; - dig.update(ctrbuf) # uint8_t ctr[4]; + dig.update(app_id) # uint8_t appId[32]; + dig.update(flags) # uint8_t flags; + dig.update(ctrbuf) # uint8_t ctr[4]; dig.update(challenge) # uint8_t chal[32]; dig = dig.digest() @@ -721,12 +729,12 @@ def msg_authenticate_sign(challenge: bytes, app_id: bytes, privkey: bytes) -> by def msg_version(req: Msg) -> Cmd: if req.data: return msg_error(req.cid, _SW_WRONG_LENGTH) - return Cmd(req.cid, _CMD_MSG, b'U2F_V2\x90\x00') # includes _SW_NO_ERROR + return Cmd(req.cid, _CMD_MSG, b"U2F_V2\x90\x00") # includes _SW_NO_ERROR def msg_error(cid: int, code: int) -> Cmd: - return Cmd(cid, _CMD_MSG, ustruct.pack('>H', code)) + return Cmd(cid, _CMD_MSG, ustruct.pack(">H", code)) def cmd_error(cid: int, code: int) -> Cmd: - return Cmd(cid, _CMD_ERROR, ustruct.pack('>B', code)) + return Cmd(cid, _CMD_ERROR, ustruct.pack(">B", code)) diff --git a/src/apps/fido_u2f/knownapps.py b/src/apps/fido_u2f/knownapps.py index aeb08f302..86f4296d2 100644 --- a/src/apps/fido_u2f/knownapps.py +++ b/src/apps/fido_u2f/knownapps.py @@ -1,19 +1,25 @@ from trezor.crypto import hashlib knownapps = { - hashlib.sha256(b'https://account.gandi.net/api/u2f/trusted_facets.json').digest(): 'Gandi', - hashlib.sha256(b'https://api-9dcf9b83.duosecurity.com').digest(): 'Duo', - hashlib.sha256(b'https://bitbucket.org').digest(): 'Bitbucket', - hashlib.sha256(b'https://dashboard.stripe.com').digest(): 'Stripe', - hashlib.sha256(b'https://demo.yubico.com').digest(): 'Yubico U2F Demo', - hashlib.sha256(b'https://github.com/u2f/trusted_facets').digest(): 'GitHub', - hashlib.sha256(b'https://gitlab.com').digest(): 'GitLab', - hashlib.sha256(b'https://keepersecurity.com').digest(): 'Keeper', - hashlib.sha256(b'https://slushpool.com/static/security/u2f.json').digest(): 'Slush Pool', - hashlib.sha256(b'https://u2f.bin.coffee').digest(): 'u2f.bin.coffee checker', - hashlib.sha256(b'https://vault.bitwarden.com/app-id.json').digest(): 'bitwarden', - hashlib.sha256(b'https://www.bitfinex.com').digest(): 'Bitfinex', - hashlib.sha256(b'https://www.dropbox.com/u2f-app-id.json').digest(): 'Dropbox', - hashlib.sha256(b'https://www.fastmail.com').digest(): 'FastMail', - hashlib.sha256(b'https://www.gstatic.com/securitykey/origins.json').digest(): 'Google', + hashlib.sha256( + b"https://account.gandi.net/api/u2f/trusted_facets.json" + ).digest(): "Gandi", + hashlib.sha256(b"https://api-9dcf9b83.duosecurity.com").digest(): "Duo", + hashlib.sha256(b"https://bitbucket.org").digest(): "Bitbucket", + hashlib.sha256(b"https://dashboard.stripe.com").digest(): "Stripe", + hashlib.sha256(b"https://demo.yubico.com").digest(): "Yubico U2F Demo", + hashlib.sha256(b"https://github.com/u2f/trusted_facets").digest(): "GitHub", + hashlib.sha256(b"https://gitlab.com").digest(): "GitLab", + hashlib.sha256(b"https://keepersecurity.com").digest(): "Keeper", + hashlib.sha256( + b"https://slushpool.com/static/security/u2f.json" + ).digest(): "Slush Pool", + hashlib.sha256(b"https://u2f.bin.coffee").digest(): "u2f.bin.coffee checker", + hashlib.sha256(b"https://vault.bitwarden.com/app-id.json").digest(): "bitwarden", + hashlib.sha256(b"https://www.bitfinex.com").digest(): "Bitfinex", + hashlib.sha256(b"https://www.dropbox.com/u2f-app-id.json").digest(): "Dropbox", + hashlib.sha256(b"https://www.fastmail.com").digest(): "FastMail", + hashlib.sha256( + b"https://www.gstatic.com/securitykey/origins.json" + ).digest(): "Google", } diff --git a/src/apps/homescreen/__init__.py b/src/apps/homescreen/__init__.py index 18202302d..ac3466b3d 100644 --- a/src/apps/homescreen/__init__.py +++ b/src/apps/homescreen/__init__.py @@ -9,15 +9,15 @@ from apps.common import cache, storage def get_features(): f = Features() - f.vendor = 'trezor.io' - f.language = 'english' - f.major_version = utils.symbol('VERSION_MAJOR') - f.minor_version = utils.symbol('VERSION_MINOR') - f.patch_version = utils.symbol('VERSION_PATCH') - f.revision = utils.symbol('GITREV') + f.vendor = "trezor.io" + f.language = "english" + f.major_version = utils.symbol("VERSION_MAJOR") + f.minor_version = utils.symbol("VERSION_MINOR") + f.patch_version = utils.symbol("VERSION_PATCH") + f.revision = utils.symbol("GITREV") f.model = utils.model() - if f.model == 'EMU': - f.model = 'T' # emulator currently emulates model T + if f.model == "EMU": + f.model = "T" # emulator currently emulates model T f.device_id = storage.get_device_id() f.label = storage.get_label() f.initialized = storage.is_initialized() @@ -42,12 +42,12 @@ async def handle_GetFeatures(ctx, msg): async def handle_Cancel(ctx, msg): - raise wire.ActionCancelled('Cancelled') + raise wire.ActionCancelled("Cancelled") async def handle_ClearSession(ctx, msg): cache.clear() - return Success(message='Session cleared') + return Success(message="Session cleared") async def handle_Ping(ctx, msg): @@ -55,9 +55,11 @@ async def handle_Ping(ctx, msg): from apps.common.confirm import require_confirm from trezor.messages.ButtonRequestType import ProtectCall from trezor.ui.text import Text - await require_confirm(ctx, Text('Confirm'), ProtectCall) + + await require_confirm(ctx, Text("Confirm"), ProtectCall) if msg.passphrase_protection: from apps.common.request_passphrase import protect_by_passphrase + await protect_by_passphrase(ctx) return Success(message=msg.message) diff --git a/src/apps/homescreen/homescreen.py b/src/apps/homescreen/homescreen.py index ab5fafc89..5eaa97f2c 100644 --- a/src/apps/homescreen/homescreen.py +++ b/src/apps/homescreen/homescreen.py @@ -14,26 +14,32 @@ async def homescreen(): def display_homescreen(): if not storage.is_initialized(): - label = 'Go to trezor.io/start' + label = "Go to trezor.io/start" image = None else: - label = storage.get_label() or 'My TREZOR' + label = storage.get_label() or "My TREZOR" image = storage.get_homescreen() if not image: - image = res.load('apps/homescreen/res/bg.toif') + image = res.load("apps/homescreen/res/bg.toif") if 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.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) 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.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) 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.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) else: ui.display.bar(0, 0, ui.WIDTH, ui.HEIGHT, ui.BG) diff --git a/src/apps/lisk/__init__.py b/src/apps/lisk/__init__.py index f20918ca4..a71453912 100644 --- a/src/apps/lisk/__init__.py +++ b/src/apps/lisk/__init__.py @@ -10,26 +10,31 @@ from trezor.wire import protobuf_workflow, register def dispatch_LiskGetAddress(*args, **kwargs): from .get_address import layout_lisk_get_address + return layout_lisk_get_address(*args, **kwargs) def dispatch_LiskGetPublicKey(*args, **kwargs): from .get_public_key import lisk_get_public_key + return lisk_get_public_key(*args, **kwargs) def dispatch_LiskSignTx(*args, **kwargs): from .sign_tx import lisk_sign_tx + return lisk_sign_tx(*args, **kwargs) def dispatch_LiskSignMessage(*args, **kwargs): from .sign_message import lisk_sign_message + return lisk_sign_message(*args, **kwargs) def dispatch_LiskVerifyMessage(*args, **kwargs): from .verify_message import lisk_verify_message + return lisk_verify_message(*args, **kwargs) diff --git a/src/apps/lisk/helpers.py b/src/apps/lisk/helpers.py index 87aa46aaa..2cca1fdb4 100644 --- a/src/apps/lisk/helpers.py +++ b/src/apps/lisk/helpers.py @@ -1,18 +1,18 @@ from trezor.crypto.hashlib import sha256 -LISK_CURVE = 'ed25519' +LISK_CURVE = "ed25519" def get_address_from_public_key(pubkey): pubkeyhash = sha256(pubkey).digest() - address = int.from_bytes(pubkeyhash[:8], 'little') - return str(address) + 'L' + address = int.from_bytes(pubkeyhash[:8], "little") + return str(address) + "L" def get_votes_count(votes): plus, minus = 0, 0 for vote in votes: - if vote.startswith('+'): + if vote.startswith("+"): plus += 1 else: minus += 1 @@ -23,11 +23,11 @@ def get_vote_tx_text(votes): plus, minus = get_votes_count(votes) text = [] if plus > 0: - text.append(_text_with_plural('Add', plus)) + text.append(_text_with_plural("Add", plus)) if minus > 0: - text.append(_text_with_plural('Remove', minus)) + text.append(_text_with_plural("Remove", minus)) return text def _text_with_plural(txt, value): - return '%s %s %s' % (txt, value, ('votes' if value != 1 else 'vote')) + return "%s %s %s" % (txt, value, ("votes" if value != 1 else "vote")) diff --git a/src/apps/lisk/layout.py b/src/apps/lisk/layout.py index 25e67c737..359a8b8d0 100644 --- a/src/apps/lisk/layout.py +++ b/src/apps/lisk/layout.py @@ -10,23 +10,23 @@ from apps.wallet.get_public_key import _show_pubkey async def require_confirm_tx(ctx, to, value): - text = Text('Confirm sending', ui.ICON_SEND, icon_color=ui.GREEN) + text = Text("Confirm sending", ui.ICON_SEND, icon_color=ui.GREEN) text.bold(format_amount(value)) - text.normal('to') + text.normal("to") text.mono(*split_address(to)) return await require_confirm(ctx, text, ButtonRequestType.SignTx) async def require_confirm_delegate_registration(ctx, delegate_name): - text = Text('Confirm transaction', ui.ICON_SEND, icon_color=ui.GREEN) - text.normal('Do you really want to') - text.normal('register a delegate?') + text = Text("Confirm transaction", ui.ICON_SEND, icon_color=ui.GREEN) + text.normal("Do you really want to") + text.normal("register a delegate?") text.bold(*chunks(delegate_name, 20)) return await require_confirm(ctx, text, ButtonRequestType.SignTx) async def require_confirm_vote_tx(ctx, votes): - text = Text('Confirm transaction', ui.ICON_SEND, icon_color=ui.GREEN) + text = Text("Confirm transaction", ui.ICON_SEND, icon_color=ui.GREEN) text.normal(*get_vote_tx_text(votes)) return await require_confirm(ctx, text, ButtonRequestType.SignTx) @@ -36,23 +36,23 @@ async def require_confirm_public_key(ctx, public_key): async def require_confirm_multisig(ctx, multisignature): - text = Text('Confirm transaction', ui.ICON_SEND, icon_color=ui.GREEN) - text.normal('Keys group length: %s' % len(multisignature.keys_group)) - text.normal('Life time: %s' % multisignature.life_time) - text.normal('Min: %s' % multisignature.min) + text = Text("Confirm transaction", ui.ICON_SEND, icon_color=ui.GREEN) + text.normal("Keys group length: %s" % len(multisignature.keys_group)) + text.normal("Life time: %s" % multisignature.life_time) + text.normal("Min: %s" % multisignature.min) return await require_confirm(ctx, text, ButtonRequestType.SignTx) async def require_confirm_fee(ctx, value, fee): - text = Text('Confirm transaction', ui.ICON_SEND, icon_color=ui.GREEN) + text = Text("Confirm transaction", ui.ICON_SEND, icon_color=ui.GREEN) text.bold(format_amount(value)) - text.normal('fee:') + text.normal("fee:") text.bold(format_amount(fee)) await require_hold_to_confirm(ctx, text, ButtonRequestType.ConfirmOutput) def format_amount(value): - return '%s LSK' % (int(value) / 100000000) + return "%s LSK" % (int(value) / 100000000) def split_address(address): diff --git a/src/apps/lisk/sign_message.py b/src/apps/lisk/sign_message.py index c48066a26..17cb2503b 100644 --- a/src/apps/lisk/sign_message.py +++ b/src/apps/lisk/sign_message.py @@ -14,7 +14,7 @@ from apps.wallet.sign_tx.signing import write_varint def message_digest(message): h = HashWriter(sha256) - signed_message_header = 'Lisk Signed Message:\n' + signed_message_header = "Lisk Signed Message:\n" write_varint(h, len(signed_message_header)) h.extend(signed_message_header) write_varint(h, len(message)) @@ -39,6 +39,6 @@ async def lisk_sign_message(ctx, msg): async def require_confirm_sign_message(ctx, message): - text = Text('Sign Lisk message') + text = Text("Sign Lisk message") text.normal(*split_message(message)) await require_confirm(ctx, text) diff --git a/src/apps/lisk/sign_tx.py b/src/apps/lisk/sign_tx.py index 330e7079d..4176aac4d 100644 --- a/src/apps/lisk/sign_tx.py +++ b/src/apps/lisk/sign_tx.py @@ -20,7 +20,7 @@ async def lisk_sign_tx(ctx, msg): try: await _require_confirm_by_type(ctx, transaction) except AttributeError: - raise wire.DataError('The transaction has invalid asset data field') + raise wire.DataError("The transaction has invalid asset data field") await layout.require_confirm_fee(ctx, transaction.amount, transaction.fee) @@ -61,48 +61,59 @@ async def _require_confirm_by_type(ctx, transaction): if transaction.type == LiskTransactionType.Transfer: return await layout.require_confirm_tx( - ctx, transaction.recipient_id, transaction.amount) + ctx, transaction.recipient_id, transaction.amount + ) if transaction.type == LiskTransactionType.RegisterDelegate: return await layout.require_confirm_delegate_registration( - ctx, transaction.asset.delegate.username) + ctx, transaction.asset.delegate.username + ) if transaction.type == LiskTransactionType.CastVotes: - return await layout.require_confirm_vote_tx( - ctx, transaction.asset.votes) + return await layout.require_confirm_vote_tx(ctx, transaction.asset.votes) if transaction.type == LiskTransactionType.RegisterSecondPassphrase: return await layout.require_confirm_public_key( - ctx, transaction.asset.signature.public_key) + ctx, transaction.asset.signature.public_key + ) if transaction.type == LiskTransactionType.RegisterMultisignatureAccount: return await layout.require_confirm_multisig( - ctx, transaction.asset.multisignature) + ctx, transaction.asset.multisignature + ) - raise wire.DataError('Invalid transaction type') + raise wire.DataError("Invalid transaction type") def _get_transaction_bytes(tx): # Required transaction parameters - t_type = ustruct.pack('Q', 0) + t_recipient_id = ustruct.pack(">Q", 0) else: # Lisk uses big-endian for recipient_id, string -> int -> bytes - t_recipient_id = ustruct.pack('>Q', int(tx.recipient_id[:-1])) + t_recipient_id = ustruct.pack(">Q", int(tx.recipient_id[:-1])) - t_amount = ustruct.pack(' storage.HOMESCREEN_MAXSIZE: - raise wire.DataError('Homescreen is too complex') + raise wire.DataError("Homescreen is too complex") await require_confirm_change_homescreen(ctx) if msg.label is not None: @@ -25,43 +30,45 @@ async def apply_settings(ctx, msg): if msg.passphrase_source is not None: await require_confirm_change_passphrase_source(ctx, msg.passphrase_source) - storage.load_settings(label=msg.label, - use_passphrase=msg.use_passphrase, - homescreen=msg.homescreen, - passphrase_source=msg.passphrase_source) + storage.load_settings( + label=msg.label, + use_passphrase=msg.use_passphrase, + homescreen=msg.homescreen, + passphrase_source=msg.passphrase_source, + ) - return Success(message='Settings applied') + return Success(message="Settings applied") async def require_confirm_change_homescreen(ctx): - text = Text('Change homescreen', ui.ICON_CONFIG) - text.normal('Do you really want to', 'change homescreen?') + text = Text("Change homescreen", ui.ICON_CONFIG) + text.normal("Do you really want to", "change homescreen?") await require_confirm(ctx, text, code=ButtonRequestType.ProtectCall) async def require_confirm_change_label(ctx, label): - text = Text('Change label', ui.ICON_CONFIG) - text.normal('Do you really want to', 'change label to') - text.bold('%s?' % label) + text = Text("Change label", ui.ICON_CONFIG) + text.normal("Do you really want to", "change label to") + text.bold("%s?" % label) await require_confirm(ctx, text, code=ButtonRequestType.ProtectCall) async def require_confirm_change_passphrase(ctx, use): - text = Text('Enable passphrase' if use else 'Disable passphrase', ui.ICON_CONFIG) - text.normal('Do you really want to') - text.normal('enable passphrase' if use else 'disable passphrase') - text.normal('encryption?') + text = Text("Enable passphrase" if use else "Disable passphrase", ui.ICON_CONFIG) + text.normal("Do you really want to") + text.normal("enable passphrase" if use else "disable passphrase") + text.normal("encryption?") await require_confirm(ctx, text, code=ButtonRequestType.ProtectCall) async def require_confirm_change_passphrase_source(ctx, source): if source == PassphraseSourceType.DEVICE: - desc = 'ON DEVICE' + desc = "ON DEVICE" elif source == PassphraseSourceType.HOST: - desc = 'ON HOST' + desc = "ON HOST" else: - desc = 'ASK' - text = Text('Passphrase source', ui.ICON_CONFIG) - text.normal('Do you really want to', 'change the passphrase', 'source to') - text.bold('ALWAYS %s?' % desc) + desc = "ASK" + text = Text("Passphrase source", ui.ICON_CONFIG) + text.normal("Do you really want to", "change the passphrase", "source to") + text.bold("ALWAYS %s?" % desc) await require_confirm(ctx, text, code=ButtonRequestType.ProtectCall) diff --git a/src/apps/management/backup_device.py b/src/apps/management/backup_device.py index d1bf8416b..4acd929c6 100644 --- a/src/apps/management/backup_device.py +++ b/src/apps/management/backup_device.py @@ -12,9 +12,9 @@ from apps.management.reset_device import ( async def backup_device(ctx, msg): if not storage.is_initialized(): - raise wire.ProcessError('Device is not initialized') + raise wire.ProcessError("Device is not initialized") if not storage.needs_backup(): - raise wire.ProcessError('Seed already backed up') + raise wire.ProcessError("Seed already backed up") mnemonic = storage.get_mnemonic() @@ -33,4 +33,4 @@ async def backup_device(ctx, msg): storage.set_unfinished_backup(False) - return Success(message='Seed successfully backed up') + return Success(message="Seed successfully backed up") diff --git a/src/apps/management/change_pin.py b/src/apps/management/change_pin.py index 307b69d52..93bcb1bd3 100644 --- a/src/apps/management/change_pin.py +++ b/src/apps/management/change_pin.py @@ -18,52 +18,52 @@ async def change_pin(ctx, msg): if config.has_pin(): curpin = await request_pin_ack(ctx) if not config.check_pin(pin_to_int(curpin), show_pin_timeout): - raise wire.PinInvalid('PIN invalid') + raise wire.PinInvalid("PIN invalid") else: - curpin = '' + curpin = "" # get new pin if not msg.remove: newpin = await request_pin_confirm(ctx) else: - newpin = '' + newpin = "" # write into storage if not config.change_pin(pin_to_int(curpin), pin_to_int(newpin), show_pin_timeout): - raise wire.PinInvalid('PIN invalid') + raise wire.PinInvalid("PIN invalid") if newpin: - return Success(message='PIN changed') + return Success(message="PIN changed") else: - return Success(message='PIN removed') + return Success(message="PIN removed") def require_confirm_change_pin(ctx, msg): has_pin = config.has_pin() if msg.remove and has_pin: # removing pin - text = Text('Remove PIN', ui.ICON_CONFIG) - text.normal('Do you really want to') - text.bold('remove current PIN?') + text = Text("Remove PIN", ui.ICON_CONFIG) + text.normal("Do you really want to") + text.bold("remove current PIN?") return require_confirm(ctx, text) if not msg.remove and has_pin: # changing pin - text = Text('Remove PIN', ui.ICON_CONFIG) - text.normal('Do you really want to') - text.bold('change current PIN?') + text = Text("Remove PIN", ui.ICON_CONFIG) + text.normal("Do you really want to") + text.bold("change current PIN?") return require_confirm(ctx, text) if not msg.remove and not has_pin: # setting new pin - text = Text('Remove PIN', ui.ICON_CONFIG) - text.normal('Do you really want to') - text.bold('set new PIN?') + text = Text("Remove PIN", ui.ICON_CONFIG) + text.normal("Do you really want to") + text.bold("set new PIN?") return require_confirm(ctx, text) async def request_pin_confirm(ctx, *args, **kwargs): while True: - pin1 = await request_pin_ack(ctx, 'Enter new PIN', *args, **kwargs) - pin2 = await request_pin_ack(ctx, 'Re-enter new PIN', *args, **kwargs) + pin1 = await request_pin_ack(ctx, "Enter new PIN", *args, **kwargs) + pin2 = await request_pin_ack(ctx, "Re-enter new PIN", *args, **kwargs) if pin1 == pin2: return pin1 await pin_mismatch() @@ -71,17 +71,19 @@ async def request_pin_confirm(ctx, *args, **kwargs): async def request_pin_ack(ctx, *args, **kwargs): try: - await ctx.call(ButtonRequest(code=ButtonRequestType.Other), MessageType.ButtonAck) + await ctx.call( + ButtonRequest(code=ButtonRequestType.Other), MessageType.ButtonAck + ) return await ctx.wait(request_pin(*args, **kwargs)) except PinCancelled: - raise wire.ActionCancelled('Cancelled') + raise wire.ActionCancelled("Cancelled") @ui.layout async def pin_mismatch(): - text = Text('PIN mismatch', ui.ICON_WRONG, icon_color=ui.RED) - text.normal('Entered PINs do not', 'match each other.') - text.normal('') - text.normal('Please, try again...') + text = Text("PIN mismatch", ui.ICON_WRONG, icon_color=ui.RED) + text.normal("Entered PINs do not", "match each other.") + text.normal("") + text.normal("Please, try again...") text.render() await loop.sleep(3 * 1000 * 1000) diff --git a/src/apps/management/load_device.py b/src/apps/management/load_device.py index e97552c3c..fb8db1741 100644 --- a/src/apps/management/load_device.py +++ b/src/apps/management/load_device.py @@ -11,24 +11,22 @@ from apps.common.confirm import require_confirm async def load_device(ctx, msg): if storage.is_initialized(): - raise wire.UnexpectedMessage('Already initialized') + raise wire.UnexpectedMessage("Already initialized") if msg.node is not None: - raise wire.ProcessError('LoadDevice.node is not supported') + raise wire.ProcessError("LoadDevice.node is not supported") if not msg.skip_checksum and not bip39.check(msg.mnemonic): - raise wire.ProcessError('Mnemonic is not valid') + raise wire.ProcessError("Mnemonic is not valid") - text = Text('Loading seed') - text.bold('Loading private seed', 'is not recommended.') - text.normal('Continue only if you', 'know what you are doing!') + text = Text("Loading seed") + text.bold("Loading private seed", "is not recommended.") + text.normal("Continue only if you", "know what you are doing!") await require_confirm(ctx, text) - storage.load_mnemonic( - mnemonic=msg.mnemonic, needs_backup=True) - storage.load_settings( - use_passphrase=msg.passphrase_protection, label=msg.label) + storage.load_mnemonic(mnemonic=msg.mnemonic, needs_backup=True) + storage.load_settings(use_passphrase=msg.passphrase_protection, label=msg.label) if msg.pin: - config.change_pin(pin_to_int(''), pin_to_int(msg.pin), None) + config.change_pin(pin_to_int(""), pin_to_int(msg.pin), None) - return Success(message='Device loaded') + return Success(message="Device loaded") diff --git a/src/apps/management/recovery_device.py b/src/apps/management/recovery_device.py index 7ea517521..9274b0e1c 100644 --- a/src/apps/management/recovery_device.py +++ b/src/apps/management/recovery_device.py @@ -15,7 +15,7 @@ from apps.management.change_pin import request_pin_confirm async def recovery_device(ctx, msg): - ''' + """ Recover BIP39 seed into empty device. 1. Ask for the number of words in recovered seed. @@ -23,9 +23,9 @@ async def recovery_device(ctx, msg): 3. Optionally check the seed validity. 4. Optionally ask for the PIN, with confirmation. 5. Save into storage. - ''' + """ if not msg.dry_run and storage.is_initialized(): - raise wire.UnexpectedMessage('Already initialized') + raise wire.UnexpectedMessage("Already initialized") # ask for the number of words wordcount = await request_wordcount(ctx) @@ -36,7 +36,7 @@ async def recovery_device(ctx, msg): # check mnemonic validity if msg.enforce_wordlist or msg.dry_run: if not bip39.check(mnemonic): - raise wire.ProcessError('Mnemonic is not valid') + raise wire.ProcessError("Mnemonic is not valid") # ask for pin repeatedly if msg.pin_protection: @@ -45,25 +45,27 @@ async def recovery_device(ctx, msg): # save into storage if not msg.dry_run: if msg.pin_protection: - config.change_pin(pin_to_int(''), pin_to_int(newpin), None) - storage.load_settings( - label=msg.label, use_passphrase=msg.passphrase_protection) - storage.load_mnemonic( - mnemonic=mnemonic, needs_backup=False) - return Success(message='Device recovered') + config.change_pin(pin_to_int(""), pin_to_int(newpin), None) + storage.load_settings(label=msg.label, use_passphrase=msg.passphrase_protection) + storage.load_mnemonic(mnemonic=mnemonic, needs_backup=False) + return Success(message="Device recovered") else: if storage.get_mnemonic() == mnemonic: - return Success(message='The seed is valid and matches the one in the device') + 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') + raise wire.ProcessError( + "The seed is valid but does not match the one in the device" + ) @ui.layout async def request_wordcount(ctx): await ctx.call(ButtonRequest(code=MnemonicWordCount), ButtonAck) - text = Text('Device recovery', ui.ICON_RECOVERY) - text.normal('Number of words?') + text = Text("Device recovery", ui.ICON_RECOVERY) + text.normal("Number of words?") count = await ctx.wait(WordSelector(text)) return count @@ -76,8 +78,8 @@ async def request_mnemonic(ctx, count: int) -> str: words = [] board = MnemonicKeyboard() for i in range(count): - board.prompt = 'Type the %s word:' % format_ordinal(i + 1) + board.prompt = "Type the %s word:" % format_ordinal(i + 1) word = await ctx.wait(board) words.append(word) - return ' '.join(words) + return " ".join(words) diff --git a/src/apps/management/reset_device.py b/src/apps/management/reset_device.py index 2c9b49f87..20d7f47e6 100644 --- a/src/apps/management/reset_device.py +++ b/src/apps/management/reset_device.py @@ -25,15 +25,15 @@ 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)') + raise wire.ProcessError("Invalid strength (has to be 128, 192 or 256 bits)") if storage.is_initialized(): - raise wire.UnexpectedMessage('Already initialized') + raise wire.UnexpectedMessage("Already initialized") # request new PIN if msg.pin_protection: newpin = await request_pin_confirm(ctx) else: - newpin = '' + newpin = "" # generate and display internal entropy internal_ent = random.bytes(32) @@ -58,14 +58,12 @@ async def reset_device(ctx, msg): await show_wrong_entry(ctx) # write PIN into storage - if not config.change_pin(pin_to_int(''), pin_to_int(newpin), None): - raise wire.ProcessError('Could not change PIN') + if not config.change_pin(pin_to_int(""), pin_to_int(newpin), None): + raise wire.ProcessError("Could not change PIN") # write settings and mnemonic into storage - storage.load_settings( - label=msg.label, use_passphrase=msg.passphrase_protection) - storage.load_mnemonic( - mnemonic=mnemonic, needs_backup=msg.skip_backup) + storage.load_settings(label=msg.label, use_passphrase=msg.passphrase_protection) + storage.load_mnemonic(mnemonic=mnemonic, needs_backup=msg.skip_backup) # show success message. if we skipped backup, it's possible that homescreen # is still running, uninterrupted. restart it to pick up new label. @@ -74,78 +72,64 @@ async def reset_device(ctx, msg): else: workflow.restartdefault() - return Success(message='Initialized') + return Success(message="Initialized") -def generate_mnemonic(strength: int, - int_entropy: bytes, - ext_entropy: bytes) -> bytes: +def generate_mnemonic(strength: int, int_entropy: bytes, ext_entropy: bytes) -> bytes: ehash = hashlib.sha256() ehash.update(int_entropy) ehash.update(ext_entropy) entropy = ehash.digest() - mnemonic = bip39.from_data(entropy[:strength // 8]) + mnemonic = bip39.from_data(entropy[: strength // 8]) return mnemonic async def show_warning(ctx): - text = Text('Backup your seed', ui.ICON_NOCOPY) + text = Text("Backup your seed", ui.ICON_NOCOPY) text.normal( - 'Never make a digital', - 'copy of your recovery', - 'seed and never upload', - 'it online!') + "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) + ctx, text, ButtonRequestType.ResetDevice, confirm="I understand", cancel=None + ) async def show_wrong_entry(ctx): - text = Text('Wrong entry!', ui.ICON_WRONG, icon_color=ui.RED) - text.normal( - 'You have entered', - 'wrong seed word.', - 'Please check again.') + text = Text("Wrong entry!", ui.ICON_WRONG, icon_color=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) + ctx, text, ButtonRequestType.ResetDevice, confirm="Check again", cancel=None + ) async def show_success(ctx): - text = Text('Backup is done!', ui.ICON_CONFIRM, icon_color=ui.GREEN) + text = Text("Backup is done!", ui.ICON_CONFIRM, icon_color=ui.GREEN) text.normal( - 'Never make a digital', - 'copy of your recovery', - 'seed and never upload', - 'it online!') + "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) + 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 = Text("Internal entropy", ui.ICON_RESET) text.mono(*lines) - await require_confirm( - ctx, - text, - ButtonRequestType.ResetDevice) + await require_confirm(ctx, text, ButtonRequestType.ResetDevice) async def show_mnemonic(ctx, mnemonic: str): await ctx.call( - ButtonRequest(code=ButtonRequestType.ResetDevice), MessageType.ButtonAck) + ButtonRequest(code=ButtonRequestType.ResetDevice), MessageType.ButtonAck + ) first_page = const(0) words_per_page = const(4) words = list(enumerate(mnemonic.split())) @@ -159,8 +143,8 @@ async def show_mnemonic_page(page: int, page_count: int, pages: list): if __debug__: debug.reset_current_words = [word for _, word in pages[page]] - lines = ['%2d. %s' % (wi + 1, word) for wi, word in pages[page]] - text = Text('Recovery seed', ui.ICON_RESET) + lines = ["%2d. %s" % (wi + 1, word) for wi, word in pages[page]] + text = Text("Recovery seed", ui.ICON_RESET) text.mono(*lines) content = Scrollpage(text, page, page_count) @@ -192,6 +176,6 @@ 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)) + keyboard = MnemonicKeyboard("Type the %s word:" % format_ordinal(index + 1)) result = await ctx.wait(keyboard) return result == words[index] diff --git a/src/apps/management/set_u2f_counter.py b/src/apps/management/set_u2f_counter.py index 49a91e6cd..e8aaada67 100644 --- a/src/apps/management/set_u2f_counter.py +++ b/src/apps/management/set_u2f_counter.py @@ -9,13 +9,13 @@ from apps.common.confirm import require_confirm async def set_u2f_counter(ctx, msg): if msg.u2f_counter is None: - raise wire.ProcessError('No value provided') + raise wire.ProcessError("No value provided") - text = Text('Set U2F counter', ui.ICON_CONFIG) - text.normal('Do you really want to', 'set the U2F counter') - text.bold('to %d?' % msg.u2f_counter) + text = Text("Set U2F counter", ui.ICON_CONFIG) + text.normal("Do you really want to", "set the U2F counter") + text.bold("to %d?" % msg.u2f_counter) await require_confirm(ctx, text, code=ButtonRequestType.ProtectCall) storage.set_u2f_counter(msg.u2f_counter) - return Success(message='U2F counter set') + return Success(message="U2F counter set") diff --git a/src/apps/management/wipe_device.py b/src/apps/management/wipe_device.py index 4308d2fe3..e8e00a032 100644 --- a/src/apps/management/wipe_device.py +++ b/src/apps/management/wipe_device.py @@ -9,15 +9,18 @@ from apps.common.confirm import require_hold_to_confirm async def wipe_device(ctx, msg): - text = Text('Wipe device', ui.ICON_WIPE, icon_color=ui.RED) - text.normal('Do you really want to', 'wipe the device?', '') - text.bold('All data will be lost.') + text = Text("Wipe device", ui.ICON_WIPE, icon_color=ui.RED) + text.normal("Do you really want to", "wipe the device?", "") + text.bold("All data will be lost.") - await require_hold_to_confirm(ctx, text, + await require_hold_to_confirm( + ctx, + text, code=ButtonRequestType.WipeDevice, button_style=ui.BTN_CANCEL, - loader_style=ui.LDR_DANGER) + loader_style=ui.LDR_DANGER, + ) storage.wipe() - return Success(message='Device wiped') + return Success(message="Device wiped") diff --git a/src/apps/nem/__init__.py b/src/apps/nem/__init__.py index ea68af2c5..dc41e4076 100644 --- a/src/apps/nem/__init__.py +++ b/src/apps/nem/__init__.py @@ -4,11 +4,13 @@ from trezor.wire import protobuf_workflow, register def dispatch_NemGetAddress(*args, **kwargs): from .get_address import get_address + return get_address(*args, **kwargs) def dispatch_NemSignTx(*args, **kwargs): from .signing import sign_tx + return sign_tx(*args, **kwargs) diff --git a/src/apps/nem/get_address.py b/src/apps/nem/get_address.py index cdbdb001a..a4894598f 100644 --- a/src/apps/nem/get_address.py +++ b/src/apps/nem/get_address.py @@ -30,7 +30,9 @@ async def get_address(ctx, msg): async def _show_address(ctx, address: str, network: int): lines = split_address(address) - text = Text('Confirm address', ui.ICON_RECEIVE, icon_color=ui.GREEN) - text.normal('%s network' % get_network_str(network)) + text = Text("Confirm address", ui.ICON_RECEIVE, icon_color=ui.GREEN) + text.normal("%s network" % get_network_str(network)) text.mono(*lines) - return await confirm(ctx, text, code=ButtonRequestType.Address, cancel='QR', cancel_style=ui.BTN_KEY) + return await confirm( + ctx, text, code=ButtonRequestType.Address, cancel="QR", cancel_style=ui.BTN_KEY + ) diff --git a/src/apps/nem/helpers.py b/src/apps/nem/helpers.py index cc2b4ad68..fa367534b 100644 --- a/src/apps/nem/helpers.py +++ b/src/apps/nem/helpers.py @@ -3,7 +3,7 @@ from micropython import const NEM_NETWORK_MAINNET = const(0x68) NEM_NETWORK_TESTNET = const(0x98) NEM_NETWORK_MIJIN = const(0x60) -NEM_CURVE = 'ed25519-keccak' +NEM_CURVE = "ed25519-keccak" NEM_TRANSACTION_TYPE_TRANSFER = const(0x0101) NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER = const(0x0801) @@ -19,7 +19,7 @@ NEM_MAX_SUPPLY = const(9000000000) NEM_SALT_SIZE = const(32) AES_BLOCK_SIZE = const(16) -NEM_HASH_ALG = 'keccak' +NEM_HASH_ALG = "keccak" NEM_PUBLIC_KEY_SIZE = const(32) # ed25519 public key NEM_LEVY_PERCENTILE_DIVISOR_ABSOLUTE = const(10000) NEM_MOSAIC_AMOUNT_DIVISOR = const(1000000) @@ -30,8 +30,8 @@ NEM_MAX_ENCRYPTED_PAYLOAD_SIZE = const(960) def get_network_str(network: int) -> str: if network == NEM_NETWORK_MAINNET: - return 'Mainnet' + return "Mainnet" elif network == NEM_NETWORK_TESTNET: - return 'Testnet' + return "Testnet" elif network == NEM_NETWORK_MIJIN: - return 'Mijin' + return "Mijin" diff --git a/src/apps/nem/layout.py b/src/apps/nem/layout.py index d1fb77cdf..52edde84e 100644 --- a/src/apps/nem/layout.py +++ b/src/apps/nem/layout.py @@ -10,15 +10,17 @@ from apps.common.confirm import require_confirm, require_hold_to_confirm async def require_confirm_text(ctx, action: str): words = split_words(action, 18) - await require_confirm_content(ctx, 'Confirm action', words) + await require_confirm_content(ctx, "Confirm action", words) async def require_confirm_fee(ctx, action: str, fee: int): content = ( - ui.NORMAL, action, - ui.BOLD, '%s XEM' % format_amount(fee, NEM_MAX_DIVISIBILITY), + ui.NORMAL, + action, + ui.BOLD, + "%s XEM" % format_amount(fee, NEM_MAX_DIVISIBILITY), ) - await require_confirm_content(ctx, 'Confirm fee', content) + await require_confirm_content(ctx, "Confirm fee", content) async def require_confirm_content(ctx, headline: str, content: list): @@ -28,10 +30,10 @@ async def require_confirm_content(ctx, headline: str, content: list): async def require_confirm_final(ctx, fee: int): - text = Text('Final confirm', ui.ICON_SEND, icon_color=ui.GREEN) - text.normal('Sign this transaction') - text.bold('and pay %s XEM' % format_amount(fee, NEM_MAX_DIVISIBILITY)) - text.normal('for network fee?') + text = Text("Final confirm", ui.ICON_SEND, icon_color=ui.GREEN) + text.normal("Sign this transaction") + text.bold("and pay %s XEM" % format_amount(fee, NEM_MAX_DIVISIBILITY)) + text.normal("for network fee?") # we use SignTx, not ConfirmOutput, for compatibility with T1 await require_hold_to_confirm(ctx, text, ButtonRequestType.SignTx) @@ -42,5 +44,5 @@ def split_address(address: str): def trim(payload: str, length: int) -> str: if len(payload) > length: - return payload[:length] + '..' + return payload[:length] + ".." return payload diff --git a/src/apps/nem/mosaic/__init__.py b/src/apps/nem/mosaic/__init__.py index cf53c24e3..0a152a22c 100644 --- a/src/apps/nem/mosaic/__init__.py +++ b/src/apps/nem/mosaic/__init__.py @@ -5,11 +5,15 @@ from trezor.messages.NEMTransactionCommon import NEMTransactionCommon from . import layout, serialize -async def mosaic_creation(ctx, public_key: bytes, common: NEMTransactionCommon, creation: NEMMosaicCreation) -> bytearray: +async def mosaic_creation( + ctx, public_key: bytes, common: NEMTransactionCommon, creation: NEMMosaicCreation +) -> bytearray: await layout.ask_mosaic_creation(ctx, common, creation) return serialize.serialize_mosaic_creation(common, creation, public_key) -async def supply_change(ctx, public_key: bytes, common: NEMTransactionCommon, change: NEMMosaicSupplyChange) -> bytearray: +async def supply_change( + ctx, public_key: bytes, common: NEMTransactionCommon, change: NEMMosaicSupplyChange +) -> bytearray: await layout.ask_supply_change(ctx, common, change) return serialize.serialize_mosaic_supply_change(common, change, public_key) diff --git a/src/apps/nem/mosaic/layout.py b/src/apps/nem/mosaic/layout.py index a0f76038c..1ebbea533 100644 --- a/src/apps/nem/mosaic/layout.py +++ b/src/apps/nem/mosaic/layout.py @@ -24,39 +24,55 @@ from ..layout import ( ) -async def ask_mosaic_creation(ctx, common: NEMTransactionCommon, creation: NEMMosaicCreation): - await require_confirm_content(ctx, 'Create mosaic', _creation_message(creation)) +async def ask_mosaic_creation( + ctx, common: NEMTransactionCommon, creation: NEMMosaicCreation +): + await require_confirm_content(ctx, "Create mosaic", _creation_message(creation)) await _require_confirm_properties(ctx, creation.definition) - await require_confirm_fee(ctx, 'Confirm creation fee', creation.fee) + await require_confirm_fee(ctx, "Confirm creation fee", creation.fee) await require_confirm_final(ctx, common.fee) -async def ask_supply_change(ctx, common: NEMTransactionCommon, change: NEMMosaicSupplyChange): - await require_confirm_content(ctx, 'Supply change', _supply_message(change)) +async def ask_supply_change( + ctx, common: NEMTransactionCommon, change: NEMMosaicSupplyChange +): + await require_confirm_content(ctx, "Supply change", _supply_message(change)) if change.type == NEMSupplyChangeType.SupplyChange_Decrease: - msg = 'Decrease supply by ' + str(change.delta) + ' whole units?' + msg = "Decrease supply by " + str(change.delta) + " whole units?" elif change.type == NEMSupplyChangeType.SupplyChange_Increase: - msg = 'Increase supply by ' + str(change.delta) + ' whole units?' + msg = "Increase supply by " + str(change.delta) + " whole units?" else: - raise ValueError('Invalid supply change type') + raise ValueError("Invalid supply change type") await require_confirm_text(ctx, msg) await require_confirm_final(ctx, common.fee) def _creation_message(mosaic_creation): - return [ui.NORMAL, 'Create mosaic', - ui.BOLD, mosaic_creation.definition.mosaic, - ui.NORMAL, 'under namespace', - ui.BOLD, mosaic_creation.definition.namespace] + return [ + ui.NORMAL, + "Create mosaic", + ui.BOLD, + mosaic_creation.definition.mosaic, + ui.NORMAL, + "under namespace", + ui.BOLD, + mosaic_creation.definition.namespace, + ] def _supply_message(supply_change): - return [ui.NORMAL, 'Modify supply for', - ui.BOLD, supply_change.mosaic, - ui.NORMAL, 'under namespace', - ui.BOLD, supply_change.namespace] + return [ + ui.NORMAL, + "Modify supply for", + ui.BOLD, + supply_change.mosaic, + ui.NORMAL, + "under namespace", + ui.BOLD, + supply_change.namespace, + ] async def _require_confirm_properties(ctx, definition: NEMMosaicDefinition): @@ -81,64 +97,64 @@ def _get_mosaic_properties(definition: NEMMosaicDefinition): # description if definition.description: - t = Text('Confirm properties', ui.ICON_SEND) - t.bold('Description:') + t = Text("Confirm properties", ui.ICON_SEND) + t.bold("Description:") t.normal(*split_words(trim(definition.description, 70), 22)) properties.append(t) # transferable if definition.transferable: - transferable = 'Yes' + transferable = "Yes" else: - transferable = 'No' - t = Text('Confirm properties', ui.ICON_SEND) - t.bold('Transferable?') + transferable = "No" + t = Text("Confirm properties", ui.ICON_SEND) + t.bold("Transferable?") t.normal(transferable) properties.append(t) # mutable_supply if definition.mutable_supply: - imm = 'mutable' + imm = "mutable" else: - imm = 'immutable' + imm = "immutable" if definition.supply: - t = Text('Confirm properties', ui.ICON_SEND) - t.bold('Initial supply:') + t = Text("Confirm properties", ui.ICON_SEND) + t.bold("Initial supply:") t.normal(str(definition.supply), imm) else: - t = Text('Confirm properties', ui.ICON_SEND) - t.bold('Initial supply:') + t = Text("Confirm properties", ui.ICON_SEND) + t.bold("Initial supply:") t.normal(imm) properties.append(t) # levy if definition.levy: - t = Text('Confirm properties', ui.ICON_SEND) - t.bold('Levy recipient:') + t = Text("Confirm properties", ui.ICON_SEND) + t.bold("Levy recipient:") t.mono(*split_address(definition.levy_address)) properties.append(t) - t = Text('Confirm properties', ui.ICON_SEND) - t.bold('Levy fee:') + t = Text("Confirm properties", ui.ICON_SEND) + t.bold("Levy fee:") t.normal(str(definition.fee)) - t.bold('Levy divisibility:') + t.bold("Levy divisibility:") t.normal(str(definition.divisibility)) properties.append(t) - t = Text('Confirm properties', ui.ICON_SEND) - t.bold('Levy namespace:') + t = Text("Confirm properties", ui.ICON_SEND) + t.bold("Levy namespace:") t.normal(definition.levy_namespace) - t.bold('Levy mosaic:') + t.bold("Levy mosaic:") t.normal(definition.levy_mosaic) properties.append(t) if definition.levy == NEMMosaicLevy.MosaicLevy_Absolute: - levy_type = 'absolute' + levy_type = "absolute" else: - levy_type = 'percentile' - t = Text('Confirm properties', ui.ICON_SEND) - t.bold('Levy type:') + levy_type = "percentile" + t = Text("Confirm properties", ui.ICON_SEND) + t.bold("Levy type:") t.normal(levy_type) properties.append(t) diff --git a/src/apps/nem/mosaic/serialize.py b/src/apps/nem/mosaic/serialize.py index 24cb62e72..bd2881c03 100644 --- a/src/apps/nem/mosaic/serialize.py +++ b/src/apps/nem/mosaic/serialize.py @@ -9,30 +9,51 @@ from ..helpers import ( from ..writers import write_bytes_with_length, write_common, write_uint32, write_uint64 -def serialize_mosaic_creation(common: NEMTransactionCommon, creation: NEMMosaicCreation, public_key: bytes): - w = write_common(common, bytearray(public_key), NEM_TRANSACTION_TYPE_MOSAIC_CREATION) +def serialize_mosaic_creation( + common: NEMTransactionCommon, creation: NEMMosaicCreation, public_key: bytes +): + w = write_common( + common, bytearray(public_key), NEM_TRANSACTION_TYPE_MOSAIC_CREATION + ) mosaics_w = bytearray() write_bytes_with_length(mosaics_w, bytearray(public_key)) - identifier_length = 4 + len(creation.definition.namespace) + 4 + len(creation.definition.mosaic) + identifier_length = ( + 4 + len(creation.definition.namespace) + 4 + len(creation.definition.mosaic) + ) write_uint32(mosaics_w, identifier_length) write_bytes_with_length(mosaics_w, bytearray(creation.definition.namespace)) write_bytes_with_length(mosaics_w, bytearray(creation.definition.mosaic)) write_bytes_with_length(mosaics_w, bytearray(creation.definition.description)) write_uint32(mosaics_w, 4) # number of properties - _write_property(mosaics_w, 'divisibility', creation.definition.divisibility) - _write_property(mosaics_w, 'initialSupply', creation.definition.supply) - _write_property(mosaics_w, 'supplyMutable', creation.definition.mutable_supply) - _write_property(mosaics_w, 'transferable', creation.definition.transferable) + _write_property(mosaics_w, "divisibility", creation.definition.divisibility) + _write_property(mosaics_w, "initialSupply", creation.definition.supply) + _write_property(mosaics_w, "supplyMutable", creation.definition.mutable_supply) + _write_property(mosaics_w, "transferable", creation.definition.transferable) if creation.definition.levy: - levy_identifier_length = 4 + len(creation.definition.levy_namespace) + 4 + len(creation.definition.levy_mosaic) - write_uint32(mosaics_w, 4 + 4 + len(creation.definition.levy_address) + 4 + levy_identifier_length + 8) + levy_identifier_length = ( + 4 + + len(creation.definition.levy_namespace) + + 4 + + len(creation.definition.levy_mosaic) + ) + write_uint32( + mosaics_w, + 4 + + 4 + + len(creation.definition.levy_address) + + 4 + + levy_identifier_length + + 8, + ) write_uint32(mosaics_w, creation.definition.levy) write_bytes_with_length(mosaics_w, bytearray(creation.definition.levy_address)) write_uint32(mosaics_w, levy_identifier_length) - write_bytes_with_length(mosaics_w, bytearray(creation.definition.levy_namespace)) + write_bytes_with_length( + mosaics_w, bytearray(creation.definition.levy_namespace) + ) write_bytes_with_length(mosaics_w, bytearray(creation.definition.levy_mosaic)) write_uint64(mosaics_w, creation.definition.fee) else: @@ -47,8 +68,12 @@ def serialize_mosaic_creation(common: NEMTransactionCommon, creation: NEMMosaicC return w -def serialize_mosaic_supply_change(common: NEMTransactionCommon, change: NEMMosaicSupplyChange, public_key: bytes): - w = write_common(common, bytearray(public_key), NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE) +def serialize_mosaic_supply_change( + common: NEMTransactionCommon, change: NEMMosaicSupplyChange, public_key: bytes +): + w = write_common( + common, bytearray(public_key), NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE + ) identifier_length = 4 + len(change.namespace) + 4 + len(change.mosaic) write_uint32(w, identifier_length) @@ -62,19 +87,19 @@ def serialize_mosaic_supply_change(common: NEMTransactionCommon, change: NEMMosa def _write_property(w: bytearray, name: str, value): if value is None: - if name in ('divisibility', 'initialSupply'): + if name in ("divisibility", "initialSupply"): value = 0 - elif name in ('supplyMutable', 'transferable'): + elif name in ("supplyMutable", "transferable"): value = False if type(value) == bool: if value: - value = 'true' + value = "true" else: - value = 'false' + value = "false" elif type(value) == int: value = str(value) elif type(value) != str: - raise ValueError('Incompatible value type') + raise ValueError("Incompatible value type") write_uint32(w, 4 + len(name) + 4 + len(value)) write_bytes_with_length(w, bytearray(name)) write_bytes_with_length(w, bytearray(value)) diff --git a/src/apps/nem/multisig/__init__.py b/src/apps/nem/multisig/__init__.py index 2f98386f3..ca2322bef 100644 --- a/src/apps/nem/multisig/__init__.py +++ b/src/apps/nem/multisig/__init__.py @@ -13,15 +13,19 @@ def initiate(public_key, common: NEMTransactionCommon, inner_tx: bytes) -> bytes return serialize.serialize_multisig(common, public_key, inner_tx) -def cosign(public_key, common: NEMTransactionCommon, inner_tx: bytes, signer: bytes) -> bytes: +def cosign( + public_key, common: NEMTransactionCommon, inner_tx: bytes, signer: bytes +) -> bytes: return serialize.serialize_multisig_signature(common, public_key, inner_tx, signer) -async def aggregate_modification(ctx, - public_key: bytes, - common: NEMTransactionCommon, - aggr: NEMAggregateModification, - multisig: bool): +async def aggregate_modification( + ctx, + public_key: bytes, + common: NEMTransactionCommon, + aggr: NEMAggregateModification, + multisig: bool, +): await layout.ask_aggregate_modification(ctx, common, aggr, multisig) w = serialize.serialize_aggregate_modification(common, aggr, public_key) diff --git a/src/apps/nem/multisig/layout.py b/src/apps/nem/multisig/layout.py index 25e3c0131..66493afd4 100644 --- a/src/apps/nem/multisig/layout.py +++ b/src/apps/nem/multisig/layout.py @@ -21,36 +21,38 @@ from ..layout import ( async def ask_multisig(ctx, msg: NEMSignTx): address = nem.compute_address(msg.multisig.signer, msg.transaction.network) if msg.cosigning: - await _require_confirm_address(ctx, 'Cosign transaction for', address) + await _require_confirm_address(ctx, "Cosign transaction for", address) else: - await _require_confirm_address(ctx, 'Initiate transaction for', address) - await require_confirm_fee(ctx, 'Confirm multisig fee', msg.transaction.fee) + await _require_confirm_address(ctx, "Initiate transaction for", address) + await require_confirm_fee(ctx, "Confirm multisig fee", msg.transaction.fee) -async def ask_aggregate_modification(ctx, common: NEMTransactionCommon, mod: NEMAggregateModification, multisig: bool): +async def ask_aggregate_modification( + ctx, common: NEMTransactionCommon, mod: NEMAggregateModification, multisig: bool +): if not multisig: - await require_confirm_text(ctx, 'Convert account to multisig account?') + await require_confirm_text(ctx, "Convert account to multisig account?") for m in mod.modifications: if m.type == NEMModificationType.CosignatoryModification_Add: - action = 'Add' + action = "Add" else: - action = 'Remove' + action = "Remove" address = nem.compute_address(m.public_key, common.network) - await _require_confirm_address(ctx, action + ' cosignatory', address) + await _require_confirm_address(ctx, action + " cosignatory", address) if mod.relative_change: if multisig: - action = 'Modify the number of cosignatories by ' + action = "Modify the number of cosignatories by " else: - action = 'Set minimum cosignatories to ' - await require_confirm_text(ctx, action + str(mod.relative_change) + '?') + action = "Set minimum cosignatories to " + await require_confirm_text(ctx, action + str(mod.relative_change) + "?") await require_confirm_final(ctx, common.fee) async def _require_confirm_address(ctx, action: str, address: str): - text = Text('Confirm address', ui.ICON_SEND, icon_color=ui.GREEN) + text = Text("Confirm address", ui.ICON_SEND, icon_color=ui.GREEN) text.normal(action) text.mono(*split_address(address)) await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput) diff --git a/src/apps/nem/multisig/serialize.py b/src/apps/nem/multisig/serialize.py index 7f6515471..8f3875216 100644 --- a/src/apps/nem/multisig/serialize.py +++ b/src/apps/nem/multisig/serialize.py @@ -16,10 +16,16 @@ def serialize_multisig(common: NEMTransactionCommon, public_key: bytes, inner: b return w -def serialize_multisig_signature(common: NEMTransactionCommon, public_key: bytes, - inner: bytes, address_public_key: bytes): +def serialize_multisig_signature( + common: NEMTransactionCommon, + public_key: bytes, + inner: bytes, + address_public_key: bytes, +): address = nem.compute_address(address_public_key, common.network) - w = write_common(common, bytearray(public_key), NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE) + w = write_common( + common, bytearray(public_key), NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE + ) digest = hashlib.sha3_256(inner).digest(True) write_uint32(w, 4 + len(digest)) @@ -28,20 +34,26 @@ def serialize_multisig_signature(common: NEMTransactionCommon, public_key: bytes return w -def serialize_aggregate_modification(common: NEMTransactionCommon, mod: NEMAggregateModification, public_key: bytes): +def serialize_aggregate_modification( + common: NEMTransactionCommon, mod: NEMAggregateModification, public_key: bytes +): version = common.network << 24 | 1 if mod.relative_change: version = common.network << 24 | 2 - w = write_common(common, - bytearray(public_key), - NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION, - version) + w = write_common( + common, + bytearray(public_key), + NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION, + version, + ) write_uint32(w, len(mod.modifications)) return w -def serialize_cosignatory_modification(w: bytearray, type: int, cosignatory_pubkey: bytes): +def serialize_cosignatory_modification( + w: bytearray, type: int, cosignatory_pubkey: bytes +): write_uint32(w, 4 + 4 + len(cosignatory_pubkey)) write_uint32(w, type) write_bytes_with_length(w, bytearray(cosignatory_pubkey)) diff --git a/src/apps/nem/namespace/__init__.py b/src/apps/nem/namespace/__init__.py index 75dd27008..d61bcd315 100644 --- a/src/apps/nem/namespace/__init__.py +++ b/src/apps/nem/namespace/__init__.py @@ -4,6 +4,11 @@ from trezor.messages.NEMTransactionCommon import NEMTransactionCommon from . import layout, serialize -async def namespace(ctx, public_key: bytes, common: NEMTransactionCommon, namespace: NEMProvisionNamespace) -> bytearray: +async def namespace( + ctx, + public_key: bytes, + common: NEMTransactionCommon, + namespace: NEMProvisionNamespace, +) -> bytearray: await layout.ask_provision_namespace(ctx, common, namespace) return serialize.serialize_provision_namespace(common, namespace, public_key) diff --git a/src/apps/nem/namespace/layout.py b/src/apps/nem/namespace/layout.py index 8e262501e..bc94360bc 100644 --- a/src/apps/nem/namespace/layout.py +++ b/src/apps/nem/namespace/layout.py @@ -4,18 +4,25 @@ from trezor.messages import NEMProvisionNamespace, NEMTransactionCommon from ..layout import require_confirm_content, require_confirm_fee, require_confirm_final -async def ask_provision_namespace(ctx, common: NEMTransactionCommon, namespace: NEMProvisionNamespace): +async def ask_provision_namespace( + ctx, common: NEMTransactionCommon, namespace: NEMProvisionNamespace +): if namespace.parent: - content = (ui.NORMAL, 'Create namespace', - ui.BOLD, namespace.namespace, - ui.NORMAL, 'under namespace', - ui.BOLD, namespace.parent) - await require_confirm_content(ctx, 'Confirm namespace', content) + content = ( + ui.NORMAL, + "Create namespace", + ui.BOLD, + namespace.namespace, + ui.NORMAL, + "under namespace", + ui.BOLD, + namespace.parent, + ) + await require_confirm_content(ctx, "Confirm namespace", content) else: - content = (ui.NORMAL, 'Create namespace', - ui.BOLD, namespace.namespace) - await require_confirm_content(ctx, 'Confirm namespace', content) + content = (ui.NORMAL, "Create namespace", ui.BOLD, namespace.namespace) + await require_confirm_content(ctx, "Confirm namespace", content) - await require_confirm_fee(ctx, 'Confirm rental fee', namespace.fee) + await require_confirm_fee(ctx, "Confirm rental fee", namespace.fee) await require_confirm_final(ctx, common.fee) diff --git a/src/apps/nem/namespace/serialize.py b/src/apps/nem/namespace/serialize.py index 0cf6fd31b..c34cd4530 100644 --- a/src/apps/nem/namespace/serialize.py +++ b/src/apps/nem/namespace/serialize.py @@ -5,10 +5,12 @@ from ..helpers import NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE from ..writers import write_bytes_with_length, write_common, write_uint32, write_uint64 -def serialize_provision_namespace(common: NEMTransactionCommon, namespace: NEMProvisionNamespace, public_key: bytes) -> bytearray: - tx = write_common(common, - bytearray(public_key), - NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE) +def serialize_provision_namespace( + common: NEMTransactionCommon, namespace: NEMProvisionNamespace, public_key: bytes +) -> bytearray: + tx = write_common( + common, bytearray(public_key), NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE + ) write_bytes_with_length(tx, bytearray(namespace.sink)) write_uint64(tx, namespace.fee) diff --git a/src/apps/nem/signing.py b/src/apps/nem/signing.py index 00d8c601d..184ff4162 100644 --- a/src/apps/nem/signing.py +++ b/src/apps/nem/signing.py @@ -30,16 +30,26 @@ async def sign_tx(ctx, msg: NEMSignTx): elif msg.supply_change: tx = await mosaic.supply_change(ctx, public_key, common, msg.supply_change) elif msg.aggregate_modification: - tx = await multisig.aggregate_modification(ctx, public_key, common, msg.aggregate_modification, msg.multisig is not None) + tx = await multisig.aggregate_modification( + ctx, + public_key, + common, + msg.aggregate_modification, + msg.multisig is not None, + ) elif msg.importance_transfer: - tx = await transfer.importance_transfer(ctx, public_key, common, msg.importance_transfer) + tx = await transfer.importance_transfer( + ctx, public_key, common, msg.importance_transfer + ) else: - raise ValueError('No transaction provided') + raise ValueError("No transaction provided") if msg.multisig: # wrap transaction in multisig wrapper if msg.cosigning: - tx = multisig.cosign(_get_public_key(node), msg.transaction, tx, msg.multisig.signer) + tx = multisig.cosign( + _get_public_key(node), msg.transaction, tx, msg.multisig.signer + ) else: tx = multisig.initiate(_get_public_key(node), msg.transaction, tx) diff --git a/src/apps/nem/transfer/__init__.py b/src/apps/nem/transfer/__init__.py index 3986d1418..5a0a61a3a 100644 --- a/src/apps/nem/transfer/__init__.py +++ b/src/apps/nem/transfer/__init__.py @@ -5,7 +5,9 @@ from trezor.messages.NEMTransfer import NEMTransfer from . import layout, serialize -async def transfer(ctx, public_key: bytes, common: NEMTransactionCommon, transfer: NEMTransfer, node): +async def transfer( + ctx, public_key: bytes, common: NEMTransactionCommon, transfer: NEMTransfer, node +): transfer.mosaics = serialize.canonicalize_mosaics(transfer.mosaics) payload, encrypted = serialize.get_transfer_payload(transfer, node) @@ -17,6 +19,8 @@ async def transfer(ctx, public_key: bytes, common: NEMTransactionCommon, transfe return w -async def importance_transfer(ctx, public_key: bytes, common: NEMTransactionCommon, imp: NEMImportanceTransfer): +async def importance_transfer( + ctx, public_key: bytes, common: NEMTransactionCommon, imp: NEMImportanceTransfer +): await layout.ask_importance_transfer(ctx, common, imp) return serialize.serialize_importance_transfer(common, imp, public_key) diff --git a/src/apps/nem/transfer/layout.py b/src/apps/nem/transfer/layout.py index 1e03f8a41..0f5393f65 100644 --- a/src/apps/nem/transfer/layout.py +++ b/src/apps/nem/transfer/layout.py @@ -22,7 +22,13 @@ from ..mosaic.helpers import get_mosaic_definition, is_nem_xem_mosaic from apps.common.confirm import require_confirm -async def ask_transfer(ctx, common: NEMTransactionCommon, transfer: NEMTransfer, payload: bytes, encrypted: bool): +async def ask_transfer( + ctx, + common: NEMTransactionCommon, + transfer: NEMTransfer, + payload: bytes, + encrypted: bool, +): if payload: await _require_confirm_payload(ctx, transfer.payload, encrypted) for mosaic in transfer.mosaics: @@ -31,7 +37,9 @@ async def ask_transfer(ctx, common: NEMTransactionCommon, transfer: NEMTransfer, await require_confirm_final(ctx, common.fee) -async def ask_transfer_mosaic(ctx, common: NEMTransactionCommon, transfer: NEMTransfer, mosaic: NEMMosaic): +async def ask_transfer_mosaic( + ctx, common: NEMTransactionCommon, transfer: NEMTransfer, mosaic: NEMMosaic +): if is_nem_xem_mosaic(mosaic.namespace, mosaic.mosaic): return @@ -39,31 +47,38 @@ async def ask_transfer_mosaic(ctx, common: NEMTransactionCommon, transfer: NEMTr mosaic_quantity = mosaic.quantity * transfer.amount / NEM_MOSAIC_AMOUNT_DIVISOR if definition: - msg = Text('Confirm mosaic', ui.ICON_SEND, icon_color=ui.GREEN) - msg.normal('Confirm transfer of') - msg.bold(format_amount(mosaic_quantity, definition['divisibility']) + definition['ticker']) - msg.normal('of') - msg.bold(definition['name']) + msg = Text("Confirm mosaic", ui.ICON_SEND, icon_color=ui.GREEN) + msg.normal("Confirm transfer of") + msg.bold( + format_amount(mosaic_quantity, definition["divisibility"]) + + definition["ticker"] + ) + msg.normal("of") + msg.bold(definition["name"]) await require_confirm(ctx, msg, ButtonRequestType.ConfirmOutput) - if 'levy' in definition and 'fee' in definition: + if "levy" in definition and "fee" in definition: levy_msg = _get_levy_msg(definition, mosaic_quantity, common.network) - msg = Text('Confirm mosaic', ui.ICON_SEND, icon_color=ui.GREEN) - msg.normal('Confirm mosaic', 'levy fee of') + msg = Text("Confirm mosaic", ui.ICON_SEND, icon_color=ui.GREEN) + msg.normal("Confirm mosaic", "levy fee of") msg.bold(levy_msg) await require_confirm(ctx, msg, ButtonRequestType.ConfirmOutput) else: - msg = Text('Confirm mosaic', ui.ICON_SEND, icon_color=ui.RED) - msg.bold('Unknown mosaic!') - msg.normal(*split_words('Divisibility and levy cannot be shown for unknown mosaics', 22)) + msg = Text("Confirm mosaic", ui.ICON_SEND, icon_color=ui.RED) + msg.bold("Unknown mosaic!") + msg.normal( + *split_words( + "Divisibility and levy cannot be shown for unknown mosaics", 22 + ) + ) await require_confirm(ctx, msg, ButtonRequestType.ConfirmOutput) - msg = Text('Confirm mosaic', ui.ICON_SEND, icon_color=ui.GREEN) - msg.normal('Confirm transfer of') - msg.bold('%s raw units' % mosaic_quantity) - msg.normal('of') - msg.bold('%s.%s' % (mosaic.namespace, mosaic.mosaic)) + msg = Text("Confirm mosaic", ui.ICON_SEND, icon_color=ui.GREEN) + msg.normal("Confirm transfer of") + msg.bold("%s raw units" % mosaic_quantity) + msg.normal("of") + msg.bold("%s.%s" % (mosaic.namespace, mosaic.mosaic)) await require_confirm(ctx, msg, ButtonRequestType.ConfirmOutput) @@ -81,47 +96,50 @@ def _get_xem_amount(transfer: NEMTransfer): def _get_levy_msg(mosaic_definition, quantity: int, network: int) -> str: levy_definition = get_mosaic_definition( - mosaic_definition['levy_namespace'], - mosaic_definition['levy_mosaic'], - network) - if mosaic_definition['levy'] == NEMMosaicLevy.MosaicLevy_Absolute: - levy_fee = mosaic_definition['fee'] + mosaic_definition["levy_namespace"], mosaic_definition["levy_mosaic"], network + ) + if mosaic_definition["levy"] == NEMMosaicLevy.MosaicLevy_Absolute: + levy_fee = mosaic_definition["fee"] else: - levy_fee = quantity * mosaic_definition['fee'] / NEM_LEVY_PERCENTILE_DIVISOR_ABSOLUTE - return format_amount( - levy_fee, - levy_definition['divisibility'] - ) + levy_definition['ticker'] - - -async def ask_importance_transfer(ctx, common: NEMTransactionCommon, imp: NEMImportanceTransfer): + levy_fee = ( + quantity * mosaic_definition["fee"] / NEM_LEVY_PERCENTILE_DIVISOR_ABSOLUTE + ) + return ( + format_amount(levy_fee, levy_definition["divisibility"]) + + levy_definition["ticker"] + ) + + +async def ask_importance_transfer( + ctx, common: NEMTransactionCommon, imp: NEMImportanceTransfer +): if imp.mode == NEMImportanceTransferMode.ImportanceTransfer_Activate: - m = 'Activate' + m = "Activate" else: - m = 'Deactivate' - await require_confirm_text(ctx, m + ' remote harvesting?') + m = "Deactivate" + await require_confirm_text(ctx, m + " remote harvesting?") await require_confirm_final(ctx, common.fee) async def _require_confirm_transfer(ctx, recipient, value): - text = Text('Confirm transfer', ui.ICON_SEND, icon_color=ui.GREEN) - text.bold('Send %s XEM' % format_amount(value, NEM_MAX_DIVISIBILITY)) - text.normal('to') + text = Text("Confirm transfer", ui.ICON_SEND, icon_color=ui.GREEN) + text.bold("Send %s XEM" % format_amount(value, NEM_MAX_DIVISIBILITY)) + text.normal("to") text.mono(*split_address(recipient)) await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput) async def _require_confirm_payload(ctx, payload: bytes, encrypt=False): - payload = str(payload, 'utf-8') + payload = str(payload, "utf-8") if len(payload) > 48: - payload = payload[:48] + '..' + payload = payload[:48] + ".." if encrypt: - text = Text('Confirm payload', ui.ICON_SEND, icon_color=ui.GREEN) - text.bold('Encrypted:') + text = Text("Confirm payload", ui.ICON_SEND, icon_color=ui.GREEN) + text.bold("Encrypted:") text.normal(*split_words(payload, 22)) else: - text = Text('Confirm payload', ui.ICON_SEND, icon_color=ui.RED) - text.bold('Unencrypted:') + text = Text("Confirm payload", ui.ICON_SEND, icon_color=ui.RED) + text.bold("Unencrypted:") text.normal(*split_words(payload, 22)) await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput) diff --git a/src/apps/nem/transfer/serialize.py b/src/apps/nem/transfer/serialize.py index ef6943d7b..23e4bf842 100644 --- a/src/apps/nem/transfer/serialize.py +++ b/src/apps/nem/transfer/serialize.py @@ -13,14 +13,19 @@ from ..helpers import ( from ..writers import write_bytes_with_length, write_common, write_uint32, write_uint64 -def serialize_transfer(common: NEMTransactionCommon, - transfer: NEMTransfer, - public_key: bytes, - payload: bytes = None, - encrypted: bool = False) -> bytearray: - tx = write_common(common, bytearray(public_key), - NEM_TRANSACTION_TYPE_TRANSFER, - _get_version(common.network, transfer.mosaics)) +def serialize_transfer( + common: NEMTransactionCommon, + transfer: NEMTransfer, + public_key: bytes, + payload: bytes = None, + encrypted: bool = False, +) -> bytearray: + tx = write_common( + common, + bytearray(public_key), + NEM_TRANSACTION_TYPE_TRANSFER, + _get_version(common.network, transfer.mosaics), + ) write_bytes_with_length(tx, bytearray(transfer.recipient)) write_uint64(tx, transfer.amount) @@ -52,11 +57,12 @@ def serialize_mosaic(w: bytearray, namespace: str, mosaic: str, quantity: int): write_uint64(w, quantity) -def serialize_importance_transfer(common: NEMTransactionCommon, - imp: NEMImportanceTransfer, - public_key: bytes) -> bytearray: - w = write_common(common, bytearray(public_key), - NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER) +def serialize_importance_transfer( + common: NEMTransactionCommon, imp: NEMImportanceTransfer, public_key: bytes +) -> bytearray: + w = write_common( + common, bytearray(public_key), NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER + ) write_uint32(w, imp.mode) write_bytes_with_length(w, bytearray(imp.public_key)) @@ -68,7 +74,7 @@ def get_transfer_payload(transfer: NEMTransfer, node) -> [bytes, bool]: encrypted = False if transfer.public_key is not None: if payload is None: - raise ValueError('Public key provided but no payload to encrypt') + raise ValueError("Public key provided but no payload to encrypt") payload = _encrypt(node, transfer.public_key, transfer.payload) encrypted = True diff --git a/src/apps/nem/validators.py b/src/apps/nem/validators.py index 702ebb814..50d4bce6e 100644 --- a/src/apps/nem/validators.py +++ b/src/apps/nem/validators.py @@ -26,7 +26,7 @@ from .helpers import ( def validate(msg: NEMSignTx): if msg.transaction is None: - raise ProcessError('No common provided') + raise ProcessError("No common provided") _validate_single_tx(msg) _validate_common(msg.transaction) @@ -35,7 +35,7 @@ def validate(msg: NEMSignTx): _validate_common(msg.multisig, True) _validate_multisig(msg.multisig, msg.transaction.network) if not msg.multisig and msg.cosigning: - raise ProcessError('No multisig transaction to cosign') + raise ProcessError("No multisig transaction to cosign") if msg.transfer: _validate_transfer(msg.transfer, msg.transaction.network) @@ -46,7 +46,9 @@ def validate(msg: NEMSignTx): if msg.supply_change: _validate_supply_change(msg.supply_change) if msg.aggregate_modification: - _validate_aggregate_modification(msg.aggregate_modification, msg.multisig is None) + _validate_aggregate_modification( + msg.aggregate_modification, msg.multisig is None + ) if msg.importance_transfer: _validate_importance_transfer(msg.importance_transfer) @@ -55,23 +57,24 @@ def validate_network(network: int) -> int: if network is None: return NEM_NETWORK_MAINNET if network not in (NEM_NETWORK_MAINNET, NEM_NETWORK_TESTNET, NEM_NETWORK_MIJIN): - raise ProcessError('Invalid NEM network') + raise ProcessError("Invalid NEM network") return network def _validate_single_tx(msg: NEMSignTx): # ensure exactly one transaction is provided - tx_count = \ - bool(msg.transfer) + \ - bool(msg.provision_namespace) + \ - bool(msg.mosaic_creation) + \ - bool(msg.supply_change) + \ - bool(msg.aggregate_modification) + \ - bool(msg.importance_transfer) + tx_count = ( + bool(msg.transfer) + + bool(msg.provision_namespace) + + bool(msg.mosaic_creation) + + bool(msg.supply_change) + + bool(msg.aggregate_modification) + + bool(msg.importance_transfer) + ) if tx_count == 0: - raise ProcessError('No transaction provided') + raise ProcessError("No transaction provided") if tx_count > 1: - raise ProcessError('More than one transaction provided') + raise ProcessError("More than one transaction provided") def _validate_common(common: NEMTransactionCommon, inner: bool = False): @@ -79,174 +82,196 @@ def _validate_common(common: NEMTransactionCommon, inner: bool = False): err = None if common.timestamp is None: - err = 'timestamp' + err = "timestamp" if common.fee is None: - err = 'fee' + err = "fee" if common.deadline is None: - err = 'deadline' + err = "deadline" if not inner and common.signer: - raise ProcessError('Signer not allowed in outer transaction') + raise ProcessError("Signer not allowed in outer transaction") if inner and common.signer is None: - err = 'signer' + err = "signer" if err: if inner: - raise ProcessError('No %s provided in inner transaction' % err) + raise ProcessError("No %s provided in inner transaction" % err) else: - raise ProcessError('No %s provided' % err) + raise ProcessError("No %s provided" % err) if common.signer is not None: - _validate_public_key(common.signer, 'Invalid signer public key in inner transaction') + _validate_public_key( + common.signer, "Invalid signer public key in inner transaction" + ) def _validate_public_key(public_key: bytes, err_msg: str): if not public_key: - raise ProcessError('%s (none provided)' % err_msg) + raise ProcessError("%s (none provided)" % err_msg) if len(public_key) != NEM_PUBLIC_KEY_SIZE: - raise ProcessError('%s (invalid length)' % err_msg) + raise ProcessError("%s (invalid length)" % err_msg) def _validate_importance_transfer(importance_transfer: NEMImportanceTransfer): if importance_transfer.mode is None: - raise ProcessError('No mode provided') - _validate_public_key(importance_transfer.public_key, 'Invalid remote account public key provided') + raise ProcessError("No mode provided") + _validate_public_key( + importance_transfer.public_key, "Invalid remote account public key provided" + ) def _validate_multisig(multisig: NEMTransactionCommon, network: int): if multisig.network != network: - raise ProcessError('Inner transaction network is different') - _validate_public_key(multisig.signer, 'Invalid multisig signer public key provided') + raise ProcessError("Inner transaction network is different") + _validate_public_key(multisig.signer, "Invalid multisig signer public key provided") def _validate_aggregate_modification( - aggregate_modification: NEMAggregateModification, - creation: bool = False): + aggregate_modification: NEMAggregateModification, creation: bool = False +): if creation and not aggregate_modification.modifications: - raise ProcessError('No modifications provided') + raise ProcessError("No modifications provided") for m in aggregate_modification.modifications: if not m.type: - raise ProcessError('No modification type provided') + raise ProcessError("No modification type provided") if m.type not in ( NEMModificationType.CosignatoryModification_Add, - NEMModificationType.CosignatoryModification_Delete + NEMModificationType.CosignatoryModification_Delete, ): - raise ProcessError('Unknown aggregate modification') + raise ProcessError("Unknown aggregate modification") if creation and m.type == NEMModificationType.CosignatoryModification_Delete: - raise ProcessError('Cannot remove cosignatory when converting account') - _validate_public_key(m.public_key, 'Invalid cosignatory public key provided') + raise ProcessError("Cannot remove cosignatory when converting account") + _validate_public_key(m.public_key, "Invalid cosignatory public key provided") def _validate_supply_change(supply_change: NEMMosaicSupplyChange): if supply_change.namespace is None: - raise ProcessError('No namespace provided') + raise ProcessError("No namespace provided") if supply_change.mosaic is None: - raise ProcessError('No mosaic provided') + raise ProcessError("No mosaic provided") if supply_change.type is None: - raise ProcessError('No type provided') - elif supply_change.type not in [NEMSupplyChangeType.SupplyChange_Decrease, NEMSupplyChangeType.SupplyChange_Increase]: - raise ProcessError('Invalid supply change type') + raise ProcessError("No type provided") + elif supply_change.type not in [ + NEMSupplyChangeType.SupplyChange_Decrease, + NEMSupplyChangeType.SupplyChange_Increase, + ]: + raise ProcessError("Invalid supply change type") if supply_change.delta is None: - raise ProcessError('No delta provided') + raise ProcessError("No delta provided") def _validate_mosaic_creation(mosaic_creation: NEMMosaicCreation, network: int): if mosaic_creation.definition is None: - raise ProcessError('No mosaic definition provided') + raise ProcessError("No mosaic definition provided") if mosaic_creation.sink is None: - raise ProcessError('No creation sink provided') + raise ProcessError("No creation sink provided") if mosaic_creation.fee is None: - raise ProcessError('No creation sink fee provided') + raise ProcessError("No creation sink fee provided") if not nem.validate_address(mosaic_creation.sink, network): - raise ProcessError('Invalid creation sink address') + raise ProcessError("Invalid creation sink address") if mosaic_creation.definition.name is not None: - raise ProcessError('Name not allowed in mosaic creation transactions') + raise ProcessError("Name not allowed in mosaic creation transactions") if mosaic_creation.definition.ticker is not None: - raise ProcessError('Ticker not allowed in mosaic creation transactions') + raise ProcessError("Ticker not allowed in mosaic creation transactions") if mosaic_creation.definition.networks: - raise ProcessError('Networks not allowed in mosaic creation transactions') + raise ProcessError("Networks not allowed in mosaic creation transactions") if mosaic_creation.definition.namespace is None: - raise ProcessError('No mosaic namespace provided') + raise ProcessError("No mosaic namespace provided") if mosaic_creation.definition.mosaic is None: - raise ProcessError('No mosaic name provided') - - if mosaic_creation.definition.supply is not None and mosaic_creation.definition.divisibility is None: - raise ProcessError('Definition divisibility needs to be provided when supply is') - if mosaic_creation.definition.supply is None and mosaic_creation.definition.divisibility is not None: - raise ProcessError('Definition supply needs to be provided when divisibility is') + raise ProcessError("No mosaic name provided") + + if ( + mosaic_creation.definition.supply is not None + and mosaic_creation.definition.divisibility is None + ): + raise ProcessError( + "Definition divisibility needs to be provided when supply is" + ) + if ( + mosaic_creation.definition.supply is None + and mosaic_creation.definition.divisibility is not None + ): + raise ProcessError( + "Definition supply needs to be provided when divisibility is" + ) if mosaic_creation.definition.levy is not None: if mosaic_creation.definition.fee is None: - raise ProcessError('No levy fee provided') + raise ProcessError("No levy fee provided") if mosaic_creation.definition.levy_address is None: - raise ProcessError('No levy address provided') + raise ProcessError("No levy address provided") if mosaic_creation.definition.levy_namespace is None: - raise ProcessError('No levy namespace provided') + raise ProcessError("No levy namespace provided") if mosaic_creation.definition.levy_mosaic is None: - raise ProcessError('No levy mosaic name provided') + raise ProcessError("No levy mosaic name provided") if mosaic_creation.definition.divisibility is None: - raise ProcessError('No divisibility provided') + raise ProcessError("No divisibility provided") if mosaic_creation.definition.supply is None: - raise ProcessError('No supply provided') + raise ProcessError("No supply provided") if mosaic_creation.definition.mutable_supply is None: - raise ProcessError('No supply mutability provided') + raise ProcessError("No supply mutability provided") if mosaic_creation.definition.transferable is None: - raise ProcessError('No mosaic transferability provided') + raise ProcessError("No mosaic transferability provided") if mosaic_creation.definition.description is None: - raise ProcessError('No description provided') + raise ProcessError("No description provided") if mosaic_creation.definition.divisibility > NEM_MAX_DIVISIBILITY: - raise ProcessError('Invalid divisibility provided') + raise ProcessError("Invalid divisibility provided") if mosaic_creation.definition.supply > NEM_MAX_SUPPLY: - raise ProcessError('Invalid supply provided') + raise ProcessError("Invalid supply provided") if not nem.validate_address(mosaic_creation.definition.levy_address, network): - raise ProcessError('Invalid levy address') + raise ProcessError("Invalid levy address") -def _validate_provision_namespace(provision_namespace: NEMProvisionNamespace, network: int): +def _validate_provision_namespace( + provision_namespace: NEMProvisionNamespace, network: int +): if provision_namespace.namespace is None: - raise ProcessError('No namespace provided') + raise ProcessError("No namespace provided") if provision_namespace.sink is None: - raise ProcessError('No rental sink provided') + raise ProcessError("No rental sink provided") if provision_namespace.fee is None: - raise ProcessError('No rental sink fee provided') + raise ProcessError("No rental sink fee provided") if not nem.validate_address(provision_namespace.sink, network): - raise ProcessError('Invalid rental sink address') + raise ProcessError("Invalid rental sink address") def _validate_transfer(transfer: NEMTransfer, network: int): if transfer.recipient is None: - raise ProcessError('No recipient provided') + raise ProcessError("No recipient provided") if transfer.amount is None: - raise ProcessError('No amount provided') + raise ProcessError("No amount provided") if transfer.public_key is not None: - _validate_public_key(transfer.public_key, 'Invalid recipient public key') + _validate_public_key(transfer.public_key, "Invalid recipient public key") if transfer.payload is None: - raise ProcessError('Public key provided but no payload to encrypt') + raise ProcessError("Public key provided but no payload to encrypt") if transfer.payload: if len(transfer.payload) > NEM_MAX_PLAIN_PAYLOAD_SIZE: - raise ProcessError('Payload too large') - if transfer.public_key and len(transfer.payload) > NEM_MAX_ENCRYPTED_PAYLOAD_SIZE: - raise ProcessError('Payload too large') + raise ProcessError("Payload too large") + if ( + transfer.public_key + and len(transfer.payload) > NEM_MAX_ENCRYPTED_PAYLOAD_SIZE + ): + raise ProcessError("Payload too large") if not nem.validate_address(transfer.recipient, network): - raise ProcessError('Invalid recipient address') + raise ProcessError("Invalid recipient address") for m in transfer.mosaics: if m.namespace is None: - raise ProcessError('No mosaic namespace provided') + raise ProcessError("No mosaic namespace provided") if m.mosaic is None: - raise ProcessError('No mosaic name provided') + raise ProcessError("No mosaic name provided") if m.quantity is None: - raise ProcessError('No mosaic quantity provided') + raise ProcessError("No mosaic quantity provided") diff --git a/src/apps/nem/writers.py b/src/apps/nem/writers.py index 5bcb6c0c5..5e67ee19c 100644 --- a/src/apps/nem/writers.py +++ b/src/apps/nem/writers.py @@ -28,10 +28,12 @@ def write_bytes_with_length(w, buf: bytearray): write_bytes(w, buf) -def write_common(common: NEMTransactionCommon, - public_key: bytearray, - transaction_type: int, - version: int = None) -> bytearray: +def write_common( + common: NEMTransactionCommon, + public_key: bytearray, + transaction_type: int, + version: int = None, +) -> bytearray: ret = bytearray() write_uint32(ret, transaction_type) diff --git a/src/apps/wallet/__init__.py b/src/apps/wallet/__init__.py index 3a9ee0667..dac3fabc1 100644 --- a/src/apps/wallet/__init__.py +++ b/src/apps/wallet/__init__.py @@ -14,46 +14,55 @@ from trezor.wire import protobuf_workflow, register def dispatch_GetPublicKey(*args, **kwargs): from .get_public_key import get_public_key + return get_public_key(*args, **kwargs) def dispatch_GetAddress(*args, **kwargs): from .get_address import get_address + return get_address(*args, **kwargs) def dispatch_GetEntropy(*args, **kwargs): from .get_entropy import get_entropy + return get_entropy(*args, **kwargs) def dispatch_SignTx(*args, **kwargs): from .sign_tx import sign_tx + return sign_tx(*args, **kwargs) def dispatch_SignMessage(*args, **kwargs): from .sign_message import sign_message + return sign_message(*args, **kwargs) def dispatch_VerifyMessage(*args, **kwargs): from .verify_message import verify_message + return verify_message(*args, **kwargs) def dispatch_SignIdentity(*args, **kwargs): from .sign_identity import sign_identity + return sign_identity(*args, **kwargs) def dispatch_GetECDHSessionKey(*args, **kwargs): from .ecdh import get_ecdh_session_key + return get_ecdh_session_key(*args, **kwargs) def dispatch_CipherKeyValue(*args, **kwargs): from .cipher_key_value import cipher_key_value + return cipher_key_value(*args, **kwargs) diff --git a/src/apps/wallet/cipher_key_value.py b/src/apps/wallet/cipher_key_value.py index b01948679..3cde61f13 100644 --- a/src/apps/wallet/cipher_key_value.py +++ b/src/apps/wallet/cipher_key_value.py @@ -11,15 +11,15 @@ from apps.common.confirm import require_confirm async def cipher_key_value(ctx, msg): if len(msg.value) % 16 > 0: - raise wire.DataError('Value length must be a multiple of 16') + raise wire.DataError("Value length must be a multiple of 16") encrypt = msg.encrypt decrypt = not msg.encrypt if (encrypt and msg.ask_on_encrypt) or (decrypt and msg.ask_on_decrypt): if encrypt: - title = 'Encrypt value' + title = "Encrypt value" else: - title = 'Decrypt value' + title = "Decrypt value" text = Text(title) text.normal(msg.key) await require_confirm(ctx, text) @@ -31,8 +31,8 @@ async def cipher_key_value(ctx, msg): def compute_cipher_key_value(msg, seckey: bytes) -> bytes: data = msg.key - data += 'E1' if msg.ask_on_encrypt else 'E0' - data += 'D1' if msg.ask_on_decrypt else 'D0' + data += "E1" if msg.ask_on_encrypt else "E0" + data += "D1" if msg.ask_on_decrypt else "D0" data = hmac.new(seckey, data, sha512).digest() key = data[:32] if msg.iv and len(msg.iv) == 16: diff --git a/src/apps/wallet/ecdh.py b/src/apps/wallet/ecdh.py index 4b62beea6..0d1500513 100644 --- a/src/apps/wallet/ecdh.py +++ b/src/apps/wallet/ecdh.py @@ -15,7 +15,7 @@ from apps.wallet.sign_identity import ( async def get_ecdh_session_key(ctx, msg): if msg.ecdsa_curve_name is None: - msg.ecdsa_curve_name = 'secp256k1' + msg.ecdsa_curve_name = "secp256k1" identity = serialize_identity(msg.identity) @@ -24,42 +24,47 @@ async def get_ecdh_session_key(ctx, msg): address_n = get_ecdh_path(identity, msg.identity.index or 0) node = await seed.derive_node(ctx, address_n, msg.ecdsa_curve_name) - session_key = ecdh(seckey=node.private_key(), - peer_public_key=msg.peer_public_key, - curve=msg.ecdsa_curve_name) + session_key = ecdh( + seckey=node.private_key(), + peer_public_key=msg.peer_public_key, + curve=msg.ecdsa_curve_name, + ) return ECDHSessionKey(session_key=session_key) async def require_confirm_ecdh_session_key(ctx, identity): lines = chunks(serialize_identity_without_proto(identity), 18) - proto = identity.proto.upper() if identity.proto else 'identity' - text = Text('Decrypt %s' % proto) + proto = identity.proto.upper() if identity.proto else "identity" + text = Text("Decrypt %s" % proto) text.mono(*lines) await require_confirm(ctx, text) def get_ecdh_path(identity: str, index: int): - identity_hash = sha256(pack(' bytes: - if curve == 'secp256k1': + if curve == "secp256k1": from trezor.crypto.curve import secp256k1 + session_key = secp256k1.multiply(seckey, peer_public_key) - elif curve == 'nist256p1': + elif curve == "nist256p1": from trezor.crypto.curve import nist256p1 + session_key = nist256p1.multiply(seckey, peer_public_key) - elif curve == 'curve25519': + elif curve == "curve25519": from trezor.crypto.curve import curve25519 + if peer_public_key[0] != 0x40: - raise ValueError('Curve25519 public key should start with 0x40') - session_key = b'\x04' + curve25519.multiply(seckey, peer_public_key[1:]) + raise ValueError("Curve25519 public key should start with 0x40") + session_key = b"\x04" + curve25519.multiply(seckey, peer_public_key[1:]) else: - raise ValueError('Unsupported curve for ECDH: ' + curve) + raise ValueError("Unsupported curve for ECDH: " + curve) return session_key diff --git a/src/apps/wallet/get_address.py b/src/apps/wallet/get_address.py index f9e740d8c..136f73049 100644 --- a/src/apps/wallet/get_address.py +++ b/src/apps/wallet/get_address.py @@ -7,7 +7,7 @@ from apps.wallet.sign_tx import addresses async def get_address(ctx, msg): - coin_name = msg.coin_name or 'Bitcoin' + coin_name = msg.coin_name or "Bitcoin" coin = coins.by_name(coin_name) node = await seed.derive_node(ctx, msg.address_n, curve_name=coin.curve_name) @@ -18,7 +18,12 @@ async def get_address(ctx, msg): while True: if await show_address(ctx, address_short): break - if await show_qr(ctx, address.upper() if msg.script_type == InputScriptType.SPENDWITNESS else address): + if await show_qr( + ctx, + address.upper() + if msg.script_type == InputScriptType.SPENDWITNESS + else address, + ): break return Address(address=address) diff --git a/src/apps/wallet/get_entropy.py b/src/apps/wallet/get_entropy.py index 350631fad..f95323586 100644 --- a/src/apps/wallet/get_entropy.py +++ b/src/apps/wallet/get_entropy.py @@ -8,9 +8,9 @@ from apps.common.confirm import require_confirm async def get_entropy(ctx, msg): - text = Text('Confirm entropy') - text.bold('Do you really want', 'to send entropy?') - text.normal('Continue only if you', 'know what you are doing!') + text = Text("Confirm entropy") + text.bold("Do you really want", "to send entropy?") + text.normal("Continue only if you", "know what you are doing!") await require_confirm(ctx, text, code=ButtonRequestType.ProtectCall) size = min(msg.size, 1024) diff --git a/src/apps/wallet/get_public_key.py b/src/apps/wallet/get_public_key.py index 914ed9a81..2b948dcaa 100644 --- a/src/apps/wallet/get_public_key.py +++ b/src/apps/wallet/get_public_key.py @@ -12,7 +12,7 @@ from apps.common.confirm import require_confirm async def get_public_key(ctx, msg): - coin_name = msg.coin_name or 'Bitcoin' + coin_name = msg.coin_name or "Bitcoin" coin = coins.by_name(coin_name) curve_name = msg.ecdsa_curve_name @@ -23,13 +23,14 @@ async def get_public_key(ctx, msg): node_xpub = node.serialize_public(coin.xpub_magic) pubkey = node.public_key() if pubkey[0] == 1: - pubkey = b'\x00' + pubkey[1:] + pubkey = b"\x00" + pubkey[1:] node_type = HDNodeType( depth=node.depth(), child_num=node.child_num(), fingerprint=node.fingerprint(), chain_code=node.chain_code(), - public_key=pubkey) + public_key=pubkey, + ) if msg.show_display: await _show_pubkey(ctx, pubkey) @@ -39,9 +40,6 @@ async def get_public_key(ctx, msg): async def _show_pubkey(ctx, pubkey: bytes): lines = chunks(hexlify(pubkey).decode(), 18) - text = Text('Confirm public key', ui.ICON_RECEIVE, icon_color=ui.GREEN) + text = Text("Confirm public key", ui.ICON_RECEIVE, icon_color=ui.GREEN) text.mono(*lines) - return await require_confirm( - ctx, - text, - code=ButtonRequestType.PublicKey) + return await require_confirm(ctx, text, code=ButtonRequestType.PublicKey) diff --git a/src/apps/wallet/sign_identity.py b/src/apps/wallet/sign_identity.py index 020663bbb..98f2136ce 100644 --- a/src/apps/wallet/sign_identity.py +++ b/src/apps/wallet/sign_identity.py @@ -12,7 +12,7 @@ from apps.common.confirm import require_confirm async def sign_identity(ctx, msg): if msg.ecdsa_curve_name is None: - msg.ecdsa_curve_name = 'secp256k1' + msg.ecdsa_curve_name = "secp256k1" identity = serialize_identity(msg.identity) @@ -21,25 +21,40 @@ async def sign_identity(ctx, msg): address_n = get_identity_path(identity, msg.identity.index or 0) node = await seed.derive_node(ctx, address_n, msg.ecdsa_curve_name) - coin = coins.by_name('Bitcoin') - if msg.ecdsa_curve_name == 'secp256k1': + coin = coins.by_name("Bitcoin") + if msg.ecdsa_curve_name == "secp256k1": address = node.address(coin.address_type) # hardcoded bitcoin address type else: address = None pubkey = node.public_key() if pubkey[0] == 0x01: - pubkey = b'\x00' + pubkey[1:] + pubkey = b"\x00" + pubkey[1:] seckey = node.private_key() - if msg.identity.proto == 'gpg': + if msg.identity.proto == "gpg": signature = sign_challenge( - seckey, msg.challenge_hidden, msg.challenge_visual, 'gpg', msg.ecdsa_curve_name) - elif msg.identity.proto == 'ssh': + seckey, + msg.challenge_hidden, + msg.challenge_visual, + "gpg", + msg.ecdsa_curve_name, + ) + elif msg.identity.proto == "ssh": signature = sign_challenge( - seckey, msg.challenge_hidden, msg.challenge_visual, 'ssh', msg.ecdsa_curve_name) + seckey, + msg.challenge_hidden, + msg.challenge_visual, + "ssh", + msg.ecdsa_curve_name, + ) else: signature = sign_challenge( - seckey, msg.challenge_hidden, msg.challenge_visual, coin, msg.ecdsa_curve_name) + seckey, + msg.challenge_hidden, + msg.challenge_visual, + coin, + msg.ecdsa_curve_name, + ) return SignedIdentity(address=address, public_key=pubkey, signature=signature) @@ -52,22 +67,22 @@ async def require_confirm_sign_identity(ctx, identity, challenge_visual): lines.append(ui.MONO) lines.extend(chunks(serialize_identity_without_proto(identity), 18)) - proto = identity.proto.upper() if identity.proto else 'identity' - text = Text('Sign %s' % proto) + proto = identity.proto.upper() if identity.proto else "identity" + text = Text("Sign %s" % proto) text.normal(*lines) await require_confirm(ctx, text) def serialize_identity(identity): - s = '' + s = "" if identity.proto: - s += identity.proto + '://' + s += identity.proto + "://" if identity.user: - s += identity.user + '@' + s += identity.user + "@" if identity.host: s += identity.host if identity.port: - s += ':' + identity.port + s += ":" + identity.port if identity.path: s += identity.path return s @@ -82,52 +97,53 @@ def serialize_identity_without_proto(identity): def get_identity_path(identity: str, index: int): - identity_hash = sha256(pack(' bytes: +def sign_challenge( + seckey: bytes, challenge_hidden: bytes, challenge_visual: str, sigtype, curve: str +) -> bytes: from trezor.crypto.hashlib import sha256 - if curve == 'secp256k1': + + if curve == "secp256k1": from trezor.crypto.curve import secp256k1 - elif curve == 'nist256p1': + elif curve == "nist256p1": from trezor.crypto.curve import nist256p1 - elif curve == 'ed25519': + elif curve == "ed25519": from trezor.crypto.curve import ed25519 from apps.common.signverify import message_digest - if sigtype == 'gpg': + if sigtype == "gpg": data = challenge_hidden - elif sigtype == 'ssh': - if curve != 'ed25519': + elif sigtype == "ssh": + if curve != "ed25519": data = sha256(challenge_hidden).digest() else: data = challenge_hidden else: # sigtype is coin - challenge = sha256(challenge_hidden).digest() + sha256(challenge_visual).digest() + challenge = ( + sha256(challenge_hidden).digest() + sha256(challenge_visual).digest() + ) data = message_digest(sigtype, challenge) - if curve == 'secp256k1': + if curve == "secp256k1": signature = secp256k1.sign(seckey, data) - elif curve == 'nist256p1': + elif curve == "nist256p1": signature = nist256p1.sign(seckey, data) - elif curve == 'ed25519': + elif curve == "ed25519": signature = ed25519.sign(seckey, data) else: - raise ValueError('Unknown curve') + raise ValueError("Unknown curve") - if curve == 'ed25519': - signature = b'\x00' + signature - elif sigtype == 'gpg' or sigtype == 'ssh': - signature = b'\x00' + signature[1:] + if curve == "ed25519": + signature = b"\x00" + signature + elif sigtype == "gpg" or sigtype == "ssh": + signature = b"\x00" + signature[1:] return signature diff --git a/src/apps/wallet/sign_message.py b/src/apps/wallet/sign_message.py index 7f3265f3b..d4a00e7dd 100644 --- a/src/apps/wallet/sign_message.py +++ b/src/apps/wallet/sign_message.py @@ -13,7 +13,7 @@ from apps.wallet.sign_tx.addresses import get_address async def sign_message(ctx, msg): message = msg.message address_n = msg.address_n - coin_name = msg.coin_name or 'Bitcoin' + coin_name = msg.coin_name or "Bitcoin" script_type = msg.script_type or 0 coin = coins.by_name(coin_name) @@ -33,13 +33,13 @@ async def sign_message(ctx, msg): elif script_type == SPENDWITNESS: signature = bytes([signature[0] + 8]) + signature[1:] else: - raise wire.ProcessError('Unsupported script type') + raise wire.ProcessError("Unsupported script type") return MessageSignature(address=address, signature=signature) async def require_confirm_sign_message(ctx, message): message = split_message(message) - text = Text('Sign message') + text = Text("Sign message") text.normal(*message) await require_confirm(ctx, text) diff --git a/src/apps/wallet/sign_tx/addresses.py b/src/apps/wallet/sign_tx/addresses.py index d532e7f99..184124589 100644 --- a/src/apps/wallet/sign_tx/addresses.py +++ b/src/apps/wallet/sign_tx/addresses.py @@ -22,18 +22,23 @@ class AddressError(Exception): pass -def get_address(script_type: InputScriptType, coin: CoinInfo, node, multisig=None) -> str: - - if script_type == InputScriptType.SPENDADDRESS or script_type == InputScriptType.SPENDMULTISIG: +def get_address( + script_type: InputScriptType, coin: CoinInfo, node, multisig=None +) -> str: + + if ( + script_type == InputScriptType.SPENDADDRESS + or script_type == InputScriptType.SPENDMULTISIG + ): if multisig: # p2sh multisig pubkey = node.public_key() index = multisig_pubkey_index(multisig, pubkey) if index is None: - raise AddressError(FailureType.ProcessError, - 'Public key not found') + raise AddressError(FailureType.ProcessError, "Public key not found") if coin.address_type_p2sh is None: - raise AddressError(FailureType.ProcessError, - 'Multisig not enabled on this coin') + raise AddressError( + FailureType.ProcessError, "Multisig not enabled on this coin" + ) pubkeys = multisig_get_pubkeys(multisig) address = address_multisig_p2sh(pubkeys, multisig.m, coin) @@ -41,8 +46,7 @@ def get_address(script_type: InputScriptType, coin: CoinInfo, node, multisig=Non address = address_to_cashaddr(address, coin) return address if script_type == InputScriptType.SPENDMULTISIG: - raise AddressError(FailureType.ProcessError, - 'Multisig details required') + raise AddressError(FailureType.ProcessError, "Multisig details required") # p2pkh address = node.address(coin.address_type) @@ -52,8 +56,9 @@ def get_address(script_type: InputScriptType, coin: CoinInfo, node, multisig=Non elif script_type == InputScriptType.SPENDWITNESS: # native p2wpkh or native p2wsh if not coin.segwit or not coin.bech32_prefix: - raise AddressError(FailureType.ProcessError, - 'Segwit not enabled on this coin') + raise AddressError( + FailureType.ProcessError, "Segwit not enabled on this coin" + ) # native p2wsh multisig if multisig is not None: pubkeys = multisig_get_pubkeys(multisig) @@ -62,10 +67,13 @@ def get_address(script_type: InputScriptType, coin: CoinInfo, node, multisig=Non # native p2wpkh return address_p2wpkh(node.public_key(), coin.bech32_prefix) - elif script_type == InputScriptType.SPENDP2SHWITNESS: # p2wpkh or p2wsh nested in p2sh + elif ( + script_type == InputScriptType.SPENDP2SHWITNESS + ): # p2wpkh or p2wsh nested in p2sh if not coin.segwit or coin.address_type_p2sh is None: - raise AddressError(FailureType.ProcessError, - 'Segwit not enabled on this coin') + raise AddressError( + FailureType.ProcessError, "Segwit not enabled on this coin" + ) # p2wsh multisig nested in p2sh if multisig is not None: pubkeys = multisig_get_pubkeys(multisig) @@ -75,14 +83,14 @@ def get_address(script_type: InputScriptType, coin: CoinInfo, node, multisig=Non return address_p2wpkh_in_p2sh(node.public_key(), coin) else: - raise AddressError(FailureType.ProcessError, - 'Invalid script type') + raise AddressError(FailureType.ProcessError, "Invalid script type") def address_multisig_p2sh(pubkeys: bytes, m: int, coin: CoinInfo): if coin.address_type_p2sh is None: - raise AddressError(FailureType.ProcessError, - 'Multisig not enabled on this coin') + raise AddressError( + FailureType.ProcessError, "Multisig not enabled on this coin" + ) redeem_script = output_script_multisig(pubkeys, m) redeem_script_hash = sha256_ripemd160_digest(redeem_script) return address_p2sh(redeem_script_hash, coin) @@ -90,8 +98,9 @@ def address_multisig_p2sh(pubkeys: bytes, m: int, coin: CoinInfo): def address_multisig_p2wsh_in_p2sh(pubkeys: bytes, m: int, coin: CoinInfo): if coin.address_type_p2sh is None: - raise AddressError(FailureType.ProcessError, - 'Multisig not enabled on this coin') + raise AddressError( + FailureType.ProcessError, "Multisig not enabled on this coin" + ) witness_script = output_script_multisig(pubkeys, m) witness_script_hash = sha256(witness_script).digest() return address_p2wsh_in_p2sh(witness_script_hash, coin) @@ -99,8 +108,9 @@ def address_multisig_p2wsh_in_p2sh(pubkeys: bytes, m: int, coin: CoinInfo): def address_multisig_p2wsh(pubkeys: bytes, m: int, hrp: str): if not hrp: - raise AddressError(FailureType.ProcessError, - 'Multisig not enabled on this coin') + raise AddressError( + FailureType.ProcessError, "Multisig not enabled on this coin" + ) witness_script = output_script_multisig(pubkeys, m) witness_script_hash = sha256(witness_script).digest() return address_p2wsh(witness_script_hash, hrp) @@ -133,24 +143,21 @@ def address_p2wpkh(pubkey: bytes, hrp: str) -> str: pubkeyhash = ecdsa_hash_pubkey(pubkey) address = bech32.encode(hrp, _BECH32_WITVER, pubkeyhash) if address is None: - raise AddressError(FailureType.ProcessError, - 'Invalid address') + raise AddressError(FailureType.ProcessError, "Invalid address") return address def address_p2wsh(witness_script_hash: bytes, hrp: str) -> str: address = bech32.encode(hrp, _BECH32_WITVER, witness_script_hash) if address is None: - raise AddressError(FailureType.ProcessError, - 'Invalid address') + raise AddressError(FailureType.ProcessError, "Invalid address") return address def decode_bech32_address(prefix: str, address: str) -> bytes: witver, raw = bech32.decode(prefix, address) if witver != _BECH32_WITVER: - raise AddressError(FailureType.ProcessError, - 'Invalid address witness program') + raise AddressError(FailureType.ProcessError, "Invalid address witness program") return bytes(raw) @@ -162,7 +169,7 @@ def address_to_cashaddr(address: str, coin: CoinInfo) -> str: elif version == coin.address_type_p2sh: version = cashaddr.ADDRESS_TYPE_P2SH else: - raise ValueError('Unknown cashaddr address type') + raise ValueError("Unknown cashaddr address type") return cashaddr.encode(coin.cashaddr_prefix, version, data) @@ -170,7 +177,7 @@ def ecdsa_hash_pubkey(pubkey: bytes) -> bytes: if pubkey[0] == 0x04: ensure(len(pubkey) == 65) # uncompressed format elif pubkey[0] == 0x00: - ensure(len(pubkey) == 1) # point at infinity + ensure(len(pubkey) == 1) # point at infinity else: ensure(len(pubkey) == 33) # compresssed format h = sha256(pubkey).digest() @@ -179,7 +186,9 @@ def ecdsa_hash_pubkey(pubkey: bytes) -> bytes: def address_short(coin: CoinInfo, address: str) -> str: - if coin.cashaddr_prefix is not None and address.startswith(coin.cashaddr_prefix + ':'): - return address[len(coin.cashaddr_prefix) + 1:] + if coin.cashaddr_prefix is not None and address.startswith( + coin.cashaddr_prefix + ":" + ): + return address[len(coin.cashaddr_prefix) + 1 :] else: return address diff --git a/src/apps/wallet/sign_tx/helpers.py b/src/apps/wallet/sign_tx/helpers.py index 0d946b523..619dbc00e 100644 --- a/src/apps/wallet/sign_tx/helpers.py +++ b/src/apps/wallet/sign_tx/helpers.py @@ -20,14 +20,12 @@ from apps.common.coininfo import CoinInfo class UiConfirmOutput: - def __init__(self, output: TxOutputType, coin: CoinInfo): self.output = output self.coin = coin class UiConfirmTotal: - def __init__(self, spending: int, fee: int, coin: CoinInfo): self.spending = spending self.fee = fee @@ -35,14 +33,12 @@ class UiConfirmTotal: class UiConfirmFeeOverThreshold: - def __init__(self, fee: int, coin: CoinInfo): self.fee = fee self.coin = coin class UiConfirmForeignAddress: - def __init__(self, address_n: list, coin: CoinInfo): self.address_n = address_n self.coin = coin @@ -64,7 +60,7 @@ def confirm_foreign_address(address_n: list, coin: CoinInfo): return (yield UiConfirmForeignAddress(address_n, coin)) -def request_tx_meta(tx_req: TxRequest, tx_hash: bytes=None): +def request_tx_meta(tx_req: TxRequest, tx_hash: bytes = None): tx_req.request_type = TXMETA tx_req.details.tx_hash = tx_hash tx_req.details.request_index = None @@ -73,7 +69,9 @@ def request_tx_meta(tx_req: TxRequest, tx_hash: bytes=None): return sanitize_tx_meta(ack.tx) -def request_tx_extra_data(tx_req: TxRequest, offset: int, size: int, tx_hash: bytes=None): +def request_tx_extra_data( + tx_req: TxRequest, offset: int, size: int, tx_hash: bytes = None +): tx_req.request_type = TXEXTRADATA tx_req.details.extra_data_offset = offset tx_req.details.extra_data_len = size @@ -84,7 +82,7 @@ def request_tx_extra_data(tx_req: TxRequest, offset: int, size: int, tx_hash: by return ack.tx.extra_data -def request_tx_input(tx_req: TxRequest, i: int, tx_hash: bytes=None): +def request_tx_input(tx_req: TxRequest, i: int, tx_hash: bytes = None): tx_req.request_type = TXINPUT tx_req.details.request_index = i tx_req.details.tx_hash = tx_hash @@ -93,7 +91,7 @@ def request_tx_input(tx_req: TxRequest, i: int, tx_hash: bytes=None): return sanitize_tx_input(ack.tx) -def request_tx_output(tx_req: TxRequest, i: int, tx_hash: bytes=None): +def request_tx_output(tx_req: TxRequest, i: int, tx_hash: bytes = None): tx_req.request_type = TXOUTPUT tx_req.details.request_index = i tx_req.details.tx_hash = tx_hash @@ -121,7 +119,7 @@ def sanitize_sign_tx(tx: SignTx) -> SignTx: tx.lock_time = tx.lock_time if tx.lock_time is not None else 0 tx.inputs_count = tx.inputs_count if tx.inputs_count is not None else 0 tx.outputs_count = tx.outputs_count if tx.outputs_count is not None else 0 - tx.coin_name = tx.coin_name if tx.coin_name is not None else 'Bitcoin' + tx.coin_name = tx.coin_name if tx.coin_name is not None else "Bitcoin" tx.expiry = tx.expiry if tx.expiry is not None else 0 tx.overwintered = tx.overwintered if tx.overwintered is not None else False return tx diff --git a/src/apps/wallet/sign_tx/layout.py b/src/apps/wallet/sign_tx/layout.py index 523289d0f..76685885c 100644 --- a/src/apps/wallet/sign_tx/layout.py +++ b/src/apps/wallet/sign_tx/layout.py @@ -10,7 +10,7 @@ from apps.wallet.sign_tx import addresses def format_coin_amount(amount, coin): - return '%s %s' % (format_amount(amount, 8), coin.coin_shortcut) + return "%s %s" % (format_amount(amount, 8), coin.coin_shortcut) def split_address(address): @@ -25,39 +25,36 @@ async def confirm_output(ctx, output, coin): if output.script_type == OutputScriptType.PAYTOOPRETURN: data = hexlify(output.op_return_data).decode() if len(data) >= 18 * 5: - data = data[:(18 * 5 - 3)] + '...' - text = Text('OP_RETURN', ui.ICON_SEND, icon_color=ui.GREEN) + data = data[: (18 * 5 - 3)] + "..." + text = Text("OP_RETURN", ui.ICON_SEND, icon_color=ui.GREEN) text.mono(*split_op_return(data)) else: address = output.address address_short = addresses.address_short(coin, address) - text = Text('Confirm sending', ui.ICON_SEND, icon_color=ui.GREEN) - text.normal(format_coin_amount(output.amount, coin) + ' to') + text = Text("Confirm sending", ui.ICON_SEND, icon_color=ui.GREEN) + text.normal(format_coin_amount(output.amount, coin) + " to") text.mono(*split_address(address_short)) return await confirm(ctx, text, ButtonRequestType.ConfirmOutput) async def confirm_total(ctx, spending, fee, coin): - text = Text('Confirm transaction', ui.ICON_SEND, icon_color=ui.GREEN) - text.normal('Total amount:') + text = Text("Confirm transaction", ui.ICON_SEND, icon_color=ui.GREEN) + text.normal("Total amount:") text.bold(format_coin_amount(spending, coin)) - text.normal('including fee:') + text.normal("including fee:") text.bold(format_coin_amount(fee, coin)) return await hold_to_confirm(ctx, text, ButtonRequestType.SignTx) async def confirm_feeoverthreshold(ctx, fee, coin): - text = Text('High fee', ui.ICON_SEND, icon_color=ui.GREEN) - text.normal('The fee of') + text = Text("High fee", ui.ICON_SEND, icon_color=ui.GREEN) + text.normal("The fee of") text.bold(format_coin_amount(fee, coin)) - text.normal('is unexpectedly high.', 'Continue?') + text.normal("is unexpectedly high.", "Continue?") return await confirm(ctx, text, ButtonRequestType.FeeOverThreshold) async def confirm_foreign_address(ctx, address_n, coin): - text = Text('Confirm sending', ui.ICON_SEND, icon_color=ui.RED) - text.normal( - 'Trying to spend', - 'coins from another chain.', - 'Continue?') + text = Text("Confirm sending", ui.ICON_SEND, icon_color=ui.RED) + text.normal("Trying to spend", "coins from another chain.", "Continue?") return await confirm(ctx, text, ButtonRequestType.SignTx) diff --git a/src/apps/wallet/sign_tx/multisig.py b/src/apps/wallet/sign_tx/multisig.py index a9aa1804c..6c5275b67 100644 --- a/src/apps/wallet/sign_tx/multisig.py +++ b/src/apps/wallet/sign_tx/multisig.py @@ -40,12 +40,12 @@ def multisig_fingerprint(multisig: MultisigRedeemScriptType) -> bytes: n = len(pubkeys) if n < 1 or n > 15 or m < 1 or m > 15: - raise MultisigError(FailureType.DataError, 'Invalid multisig parameters') + raise MultisigError(FailureType.DataError, "Invalid multisig parameters") for hd in pubkeys: d = hd.node if len(d.public_key) != 33 or len(d.chain_code) != 32: - raise MultisigError(FailureType.DataError, 'Invalid multisig parameters') + raise MultisigError(FailureType.DataError, "Invalid multisig parameters") # casting to bytes(), sorting on bytearray() is not supported in MicroPython pubkeys = sorted(pubkeys, key=lambda hd: bytes(hd.node.public_key)) @@ -68,8 +68,7 @@ def multisig_pubkey_index(multisig: MultisigRedeemScriptType, pubkey: bytes) -> for i, hd in enumerate(multisig.pubkeys): if multisig_get_pubkey(hd) == pubkey: return i - raise MultisigError(FailureType.DataError, - 'Pubkey not found in multisig script') + raise MultisigError(FailureType.DataError, "Pubkey not found in multisig script") def multisig_get_pubkey(hd: HDNodePathType) -> bytes: @@ -80,7 +79,8 @@ def multisig_get_pubkey(hd: HDNodePathType) -> bytes: fingerprint=n.fingerprint, child_num=n.child_num, chain_code=n.chain_code, - public_key=n.public_key) + public_key=n.public_key, + ) for i in p: node.derive(i, True) return node.public_key() diff --git a/src/apps/wallet/sign_tx/overwinter_zip143.py b/src/apps/wallet/sign_tx/overwinter_zip143.py index 4b2e03da4..bc7b9d195 100644 --- a/src/apps/wallet/sign_tx/overwinter_zip143.py +++ b/src/apps/wallet/sign_tx/overwinter_zip143.py @@ -28,11 +28,10 @@ class Zip143Error(ValueError): class Zip143: - def __init__(self): - self.h_prevouts = HashWriter(blake2b, outlen=32, personal=b'ZcashPrevoutHash') - self.h_sequence = HashWriter(blake2b, outlen=32, personal=b'ZcashSequencHash') - self.h_outputs = HashWriter(blake2b, outlen=32, personal=b'ZcashOutputsHash') + self.h_prevouts = HashWriter(blake2b, outlen=32, personal=b"ZcashPrevoutHash") + self.h_sequence = HashWriter(blake2b, outlen=32, personal=b"ZcashSequencHash") + self.h_outputs = HashWriter(blake2b, outlen=32, personal=b"ZcashOutputsHash") def add_prevouts(self, txi: TxInputType): write_bytes_rev(self.h_prevouts, txi.prev_hash) @@ -53,31 +52,42 @@ class Zip143: def get_outputs_hash(self) -> bytes: return get_tx_hash(self.h_outputs) - def preimage_hash(self, coin: CoinInfo, tx: SignTx, txi: TxInputType, pubkeyhash: bytes, sighash: int) -> bytes: - h_preimage = HashWriter(blake2b, outlen=32, personal=b'ZcashSigHash\x19\x1b\xa8\x5b') # BRANCH_ID = 0x5ba81b19 + def preimage_hash( + self, + coin: CoinInfo, + tx: SignTx, + txi: TxInputType, + pubkeyhash: bytes, + sighash: int, + ) -> bytes: + h_preimage = HashWriter( + blake2b, outlen=32, personal=b"ZcashSigHash\x19\x1b\xa8\x5b" + ) # BRANCH_ID = 0x5ba81b19 assert tx.overwintered - write_uint32(h_preimage, tx.version | OVERWINTERED) # 1. nVersion | fOverwintered - write_uint32(h_preimage, coin.version_group_id) # 2. nVersionGroupId + write_uint32( + h_preimage, tx.version | OVERWINTERED + ) # 1. nVersion | fOverwintered + write_uint32(h_preimage, coin.version_group_id) # 2. nVersionGroupId write_bytes(h_preimage, bytearray(self.get_prevouts_hash())) # 3. hashPrevouts write_bytes(h_preimage, bytearray(self.get_sequence_hash())) # 4. hashSequence - write_bytes(h_preimage, bytearray(self.get_outputs_hash())) # 5. hashOutputs - write_bytes(h_preimage, b'\x00' * 32) # 6. hashJoinSplits - write_uint32(h_preimage, tx.lock_time) # 7. nLockTime - write_uint32(h_preimage, tx.expiry) # 8. expiryHeight - write_uint32(h_preimage, sighash) # 9. nHashType + write_bytes(h_preimage, bytearray(self.get_outputs_hash())) # 5. hashOutputs + write_bytes(h_preimage, b"\x00" * 32) # 6. hashJoinSplits + write_uint32(h_preimage, tx.lock_time) # 7. nLockTime + write_uint32(h_preimage, tx.expiry) # 8. expiryHeight + write_uint32(h_preimage, sighash) # 9. nHashType - write_bytes_rev(h_preimage, txi.prev_hash) # 10a. outpoint + write_bytes_rev(h_preimage, txi.prev_hash) # 10a. outpoint write_uint32(h_preimage, txi.prev_index) - script_code = self.derive_script_code(txi, pubkeyhash) # 10b. scriptCode + script_code = self.derive_script_code(txi, pubkeyhash) # 10b. scriptCode write_varint(h_preimage, len(script_code)) write_bytes(h_preimage, script_code) - write_uint64(h_preimage, txi.amount) # 10c. value + write_uint64(h_preimage, txi.amount) # 10c. value - write_uint32(h_preimage, txi.sequence) # 10d. nSequence + write_uint32(h_preimage, txi.sequence) # 10d. nSequence return get_tx_hash(h_preimage) @@ -86,12 +96,16 @@ class Zip143: def derive_script_code(self, txi: TxInputType, pubkeyhash: bytes) -> bytearray: if txi.multisig: - return output_script_multisig(multisig_get_pubkeys(txi.multisig), txi.multisig.m) + return output_script_multisig( + multisig_get_pubkeys(txi.multisig), txi.multisig.m + ) p2pkh = txi.script_type == InputScriptType.SPENDADDRESS if p2pkh: return output_script_p2pkh(pubkeyhash) else: - raise Zip143Error(FailureType.DataError, - 'Unknown input script type for zip143 script code') + raise Zip143Error( + FailureType.DataError, + "Unknown input script type for zip143 script code", + ) diff --git a/src/apps/wallet/sign_tx/progress.py b/src/apps/wallet/sign_tx/progress.py index ea0c3fca5..80918217f 100644 --- a/src/apps/wallet/sign_tx/progress.py +++ b/src/apps/wallet/sign_tx/progress.py @@ -20,7 +20,7 @@ def advance(): def report_init(): ui.display.clear() - ui.header('Signing transaction') + ui.header("Signing transaction") def report(): diff --git a/src/apps/wallet/sign_tx/scripts.py b/src/apps/wallet/sign_tx/scripts.py index 568251291..e27473434 100644 --- a/src/apps/wallet/sign_tx/scripts.py +++ b/src/apps/wallet/sign_tx/scripts.py @@ -51,7 +51,9 @@ def output_script_p2sh(scripthash: bytes) -> bytearray: return s -def script_replay_protection_bip115(block_hash: bytes, block_height: int) -> bytearray: +def script_replay_protection_bip115( + block_hash: bytes, block_height: bytes +) -> bytearray: if block_hash is None or block_height is None: return bytearray() assert len(block_hash) == 32 diff --git a/src/apps/wallet/sign_tx/segwit_bip143.py b/src/apps/wallet/sign_tx/segwit_bip143.py index 63ed06b90..c36be54ed 100644 --- a/src/apps/wallet/sign_tx/segwit_bip143.py +++ b/src/apps/wallet/sign_tx/segwit_bip143.py @@ -24,7 +24,6 @@ class Bip143Error(ValueError): class Bip143: - def __init__(self): self.h_prevouts = HashWriter(sha256) self.h_sequence = HashWriter(sha256) @@ -49,27 +48,34 @@ class Bip143: def get_outputs_hash(self, coin: CoinInfo) -> bytes: return get_tx_hash(self.h_outputs, double=coin.sign_hash_double) - def preimage_hash(self, coin: CoinInfo, tx: SignTx, txi: TxInputType, pubkeyhash: bytes, sighash: int) -> bytes: + def preimage_hash( + self, + coin: CoinInfo, + tx: SignTx, + txi: TxInputType, + pubkeyhash: bytes, + sighash: int, + ) -> bytes: h_preimage = HashWriter(sha256) assert not tx.overwintered - write_uint32(h_preimage, tx.version) # nVersion + write_uint32(h_preimage, tx.version) # nVersion write_bytes(h_preimage, bytearray(self.get_prevouts_hash(coin))) # hashPrevouts write_bytes(h_preimage, bytearray(self.get_sequence_hash(coin))) # hashSequence - write_bytes_rev(h_preimage, txi.prev_hash) # outpoint - write_uint32(h_preimage, txi.prev_index) # outpoint + write_bytes_rev(h_preimage, txi.prev_hash) # outpoint + write_uint32(h_preimage, txi.prev_index) # outpoint - script_code = self.derive_script_code(txi, pubkeyhash) # scriptCode + script_code = self.derive_script_code(txi, pubkeyhash) # scriptCode write_varint(h_preimage, len(script_code)) write_bytes(h_preimage, script_code) - write_uint64(h_preimage, txi.amount) # amount - write_uint32(h_preimage, txi.sequence) # nSequence - write_bytes(h_preimage, bytearray(self.get_outputs_hash(coin))) # hashOutputs - write_uint32(h_preimage, tx.lock_time) # nLockTime - write_uint32(h_preimage, sighash) # nHashType + write_uint64(h_preimage, txi.amount) # amount + write_uint32(h_preimage, txi.sequence) # nSequence + write_bytes(h_preimage, bytearray(self.get_outputs_hash(coin))) # hashOutputs + write_uint32(h_preimage, tx.lock_time) # nLockTime + write_uint32(h_preimage, sighash) # nHashType return get_tx_hash(h_preimage, double=coin.sign_hash_double) @@ -78,16 +84,22 @@ class Bip143: def derive_script_code(self, txi: TxInputType, pubkeyhash: bytes) -> bytearray: if txi.multisig: - return output_script_multisig(multisig_get_pubkeys(txi.multisig), txi.multisig.m) - - p2pkh = (txi.script_type == InputScriptType.SPENDWITNESS or - txi.script_type == InputScriptType.SPENDP2SHWITNESS or - txi.script_type == InputScriptType.SPENDADDRESS) + return output_script_multisig( + multisig_get_pubkeys(txi.multisig), txi.multisig.m + ) + + p2pkh = ( + txi.script_type == InputScriptType.SPENDWITNESS + or txi.script_type == InputScriptType.SPENDP2SHWITNESS + or txi.script_type == InputScriptType.SPENDADDRESS + ) if p2pkh: # for p2wpkh in p2sh or native p2wpkh # the scriptCode is a classic p2pkh return output_script_p2pkh(pubkeyhash) else: - raise Bip143Error(FailureType.DataError, - 'Unknown input script type for bip143 script code') + raise Bip143Error( + FailureType.DataError, + "Unknown input script type for bip143 script code", + ) diff --git a/src/apps/wallet/sign_tx/signing.py b/src/apps/wallet/sign_tx/signing.py index 67bad7a79..34651fa2c 100644 --- a/src/apps/wallet/sign_tx/signing.py +++ b/src/apps/wallet/sign_tx/signing.py @@ -94,35 +94,40 @@ async def check_tx_fee(tx: SignTx, root: bip32.HDNode): if txi.multisig: multifp.add(txi.multisig) - if txi.script_type in (InputScriptType.SPENDWITNESS, - InputScriptType.SPENDP2SHWITNESS): + if txi.script_type in ( + InputScriptType.SPENDWITNESS, + InputScriptType.SPENDP2SHWITNESS, + ): if not coin.segwit: - raise SigningError(FailureType.DataError, - 'Segwit not enabled on this coin') + raise SigningError( + FailureType.DataError, "Segwit not enabled on this coin" + ) if not txi.amount: - raise SigningError(FailureType.DataError, - 'Segwit input without amount') + raise SigningError(FailureType.DataError, "Segwit input without amount") segwit[i] = True segwit_in += txi.amount total_in += txi.amount - elif txi.script_type in (InputScriptType.SPENDADDRESS, - InputScriptType.SPENDMULTISIG): + elif txi.script_type in ( + InputScriptType.SPENDADDRESS, + InputScriptType.SPENDMULTISIG, + ): if coin.force_bip143 or tx.overwintered: if not txi.amount: - raise SigningError(FailureType.DataError, - 'BIP/ZIP 143 input without amount') + raise SigningError( + FailureType.DataError, "BIP/ZIP 143 input without amount" + ) segwit[i] = False segwit_in += txi.amount total_in += txi.amount else: segwit[i] = False total_in += await get_prevtx_output_value( - coin, tx_req, txi.prev_hash, txi.prev_index) + coin, tx_req, txi.prev_hash, txi.prev_index + ) else: - raise SigningError(FailureType.DataError, - 'Wrong input script type') + raise SigningError(FailureType.DataError, "Wrong input script type") for o in range(tx.outputs_count): # STAGE_REQUEST_3_OUTPUT @@ -135,8 +140,7 @@ async def check_tx_fee(tx: SignTx, root: bip32.HDNode): # output is change and does not need confirmation change_out = txo.amount elif not await confirm_output(txo, coin): - raise SigningError(FailureType.ActionCancelled, - 'Output cancelled') + raise SigningError(FailureType.ActionCancelled, "Output cancelled") write_tx_output(h_first, txo_bin) hash143.add_output(txo_bin) @@ -144,18 +148,15 @@ async def check_tx_fee(tx: SignTx, root: bip32.HDNode): fee = total_in - total_out if fee < 0: - raise SigningError(FailureType.NotEnoughFunds, - 'Not enough funds') + raise SigningError(FailureType.NotEnoughFunds, "Not enough funds") # fee > (coin.maxfee per byte * tx size) if fee > (coin.maxfee_kb / 1000) * (weight.get_total() / 4): if not await confirm_feeoverthreshold(fee, coin): - raise SigningError(FailureType.ActionCancelled, - 'Signing cancelled') + raise SigningError(FailureType.ActionCancelled, "Signing cancelled") if not await confirm_total(total_out - change_out, fee, coin): - raise SigningError(FailureType.ActionCancelled, - 'Total cancelled') + raise SigningError(FailureType.ActionCancelled, "Total cancelled") return h_first, hash143, segwit, total_in, wallet_path @@ -191,11 +192,14 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode): # STAGE_REQUEST_SEGWIT_INPUT txi_sign = await request_tx_input(tx_req, i_sign) - is_segwit = (txi_sign.script_type == InputScriptType.SPENDWITNESS or - txi_sign.script_type == InputScriptType.SPENDP2SHWITNESS) + is_segwit = ( + txi_sign.script_type == InputScriptType.SPENDWITNESS + or txi_sign.script_type == InputScriptType.SPENDP2SHWITNESS + ) if not is_segwit: - raise SigningError(FailureType.ProcessError, - 'Transaction has changed during signing') + raise SigningError( + FailureType.ProcessError, "Transaction has changed during signing" + ) input_check_wallet_path(txi_sign, wallet_path) key_sign = node_derive(root, txi_sign.address_n) @@ -203,7 +207,8 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode): txi_sign.script_sig = input_derive_script(coin, txi_sign, key_sign_pub) w_txi = bytearray_with_cap( - 7 + len(txi_sign.prev_hash) + 4 + len(txi_sign.script_sig) + 4) + 7 + len(txi_sign.prev_hash) + 4 + len(txi_sign.script_sig) + 4 + ) if i_sign == 0: # serializing first input => prepend headers write_bytes(w_txi, get_tx_header(coin, tx, True)) write_tx_input(w_txi, txi_sign) @@ -215,17 +220,21 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode): txi_sign = await request_tx_input(tx_req, i_sign) input_check_wallet_path(txi_sign, wallet_path) - is_bip143 = (txi_sign.script_type == InputScriptType.SPENDADDRESS or - txi_sign.script_type == InputScriptType.SPENDMULTISIG) + is_bip143 = ( + txi_sign.script_type == InputScriptType.SPENDADDRESS + or txi_sign.script_type == InputScriptType.SPENDMULTISIG + ) if not is_bip143 or txi_sign.amount > authorized_in: - raise SigningError(FailureType.ProcessError, - 'Transaction has changed during signing') + raise SigningError( + FailureType.ProcessError, "Transaction has changed during signing" + ) authorized_in -= txi_sign.amount key_sign = node_derive(root, txi_sign.address_n) key_sign_pub = key_sign.public_key() hash143_hash = hash143.preimage_hash( - coin, tx, txi_sign, ecdsa_hash_pubkey(key_sign_pub), get_hash_type(coin)) + coin, tx, txi_sign, ecdsa_hash_pubkey(key_sign_pub), get_hash_type(coin) + ) # if multisig, check if singing with a key that is included in multisig if txi_sign.multisig: @@ -237,9 +246,11 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode): # serialize input with correct signature txi_sign.script_sig = input_derive_script( - coin, txi_sign, key_sign_pub, signature) + coin, txi_sign, key_sign_pub, signature + ) w_txi_sign = bytearray_with_cap( - 5 + len(txi_sign.prev_hash) + 4 + len(txi_sign.script_sig) + 4) + 5 + len(txi_sign.prev_hash) + 4 + len(txi_sign.script_sig) + 4 + ) if i_sign == 0: # serializing first input => prepend headers write_bytes(w_txi_sign, get_tx_header(coin, tx)) write_tx_input(w_txi_sign, txi_sign) @@ -254,10 +265,12 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode): h_second = HashWriter(sha256) if tx.overwintered: - write_uint32(h_sign, tx.version | OVERWINTERED) # nVersion | fOverwintered - write_uint32(h_sign, coin.version_group_id) # nVersionGroupId + write_uint32( + h_sign, tx.version | OVERWINTERED + ) # nVersion | fOverwintered + write_uint32(h_sign, coin.version_group_id) # nVersionGroupId else: - write_uint32(h_sign, tx.version) # nVersion + write_uint32(h_sign, tx.version) # nVersion write_varint(h_sign, tx.inputs_count) @@ -274,15 +287,21 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode): # to the previous tx's scriptPubKey (P2PKH) or a redeem script (P2SH) if txi_sign.script_type == InputScriptType.SPENDMULTISIG: txi_sign.script_sig = output_script_multisig( - multisig_get_pubkeys(txi_sign.multisig), - txi_sign.multisig.m) + multisig_get_pubkeys(txi_sign.multisig), txi_sign.multisig.m + ) elif txi_sign.script_type == InputScriptType.SPENDADDRESS: - txi_sign.script_sig = output_script_p2pkh(ecdsa_hash_pubkey(key_sign_pub)) + txi_sign.script_sig = output_script_p2pkh( + ecdsa_hash_pubkey(key_sign_pub) + ) if coin.bip115: - txi_sign.script_sig += script_replay_protection_bip115(txi_sign.prev_block_hash_bip115, txi_sign.prev_block_height_bip115) + txi_sign.script_sig += script_replay_protection_bip115( + txi_sign.prev_block_hash_bip115, + txi_sign.prev_block_height_bip115, + ) else: - raise SigningError(FailureType.ProcessError, - 'Unknown transaction type') + raise SigningError( + FailureType.ProcessError, "Unknown transaction type" + ) else: txi.script_sig = bytes() write_tx_input(h_sign, txi) @@ -300,29 +319,34 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode): write_uint32(h_sign, tx.lock_time) if tx.overwintered: write_uint32(h_sign, tx.expiry) # expiryHeight - write_varint(h_sign, 0) # nJoinSplit + write_varint(h_sign, 0) # nJoinSplit write_uint32(h_sign, get_hash_type(coin)) # check the control digests if get_tx_hash(h_first, False) != get_tx_hash(h_second): - raise SigningError(FailureType.ProcessError, - 'Transaction has changed during signing') + raise SigningError( + FailureType.ProcessError, "Transaction has changed during signing" + ) # if multisig, check if singing with a key that is included in multisig if txi_sign.multisig: multisig_pubkey_index(txi_sign.multisig, key_sign_pub) # compute the signature from the tx digest - signature = ecdsa_sign(key_sign, get_tx_hash(h_sign, double=coin.sign_hash_double)) + signature = ecdsa_sign( + key_sign, get_tx_hash(h_sign, double=coin.sign_hash_double) + ) tx_ser.signature_index = i_sign tx_ser.signature = signature # serialize input with correct signature txi_sign.script_sig = input_derive_script( - coin, txi_sign, key_sign_pub, signature) + coin, txi_sign, key_sign_pub, signature + ) w_txi_sign = bytearray_with_cap( - 5 + len(txi_sign.prev_hash) + 4 + len(txi_sign.script_sig) + 4) + 5 + len(txi_sign.prev_hash) + 4 + len(txi_sign.script_sig) + 4 + ) if i_sign == 0: # serializing first input => prepend headers write_bytes(w_txi_sign, get_tx_header(coin, tx)) write_tx_input(w_txi_sign, txi_sign) @@ -338,8 +362,7 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode): txo_bin.script_pubkey = output_derive_script(txo, coin, root) # serialize output - w_txo_bin = bytearray_with_cap( - 5 + 8 + 5 + len(txo_bin.script_pubkey) + 4) + w_txo_bin = bytearray_with_cap(5 + 8 + 5 + len(txo_bin.script_pubkey) + 4) if o == 0: # serializing first output => prepend outputs count write_varint(w_txo_bin, tx.outputs_count) write_tx_output(w_txo_bin, txo_bin) @@ -359,23 +382,29 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode): txi = await request_tx_input(tx_req, i) input_check_wallet_path(txi, wallet_path) - is_segwit = (txi.script_type == InputScriptType.SPENDWITNESS or - txi.script_type == InputScriptType.SPENDP2SHWITNESS) + is_segwit = ( + txi.script_type == InputScriptType.SPENDWITNESS + or txi.script_type == InputScriptType.SPENDP2SHWITNESS + ) if not is_segwit or txi.amount > authorized_in: - raise SigningError(FailureType.ProcessError, - 'Transaction has changed during signing') + raise SigningError( + FailureType.ProcessError, "Transaction has changed during signing" + ) authorized_in -= txi.amount key_sign = node_derive(root, txi.address_n) key_sign_pub = key_sign.public_key() hash143_hash = hash143.preimage_hash( - coin, tx, txi, ecdsa_hash_pubkey(key_sign_pub), get_hash_type(coin)) + coin, tx, txi, ecdsa_hash_pubkey(key_sign_pub), get_hash_type(coin) + ) signature = ecdsa_sign(key_sign, hash143_hash) if txi.multisig: # find out place of our signature based on the pubkey signature_index = multisig_pubkey_index(txi.multisig, key_sign_pub) - witness = witness_p2wsh(txi.multisig, signature, signature_index, get_hash_type(coin)) + witness = witness_p2wsh( + txi.multisig, signature, signature_index, get_hash_type(coin) + ) else: witness = witness_p2wpkh(signature, key_sign_pub, get_hash_type(coin)) @@ -392,12 +421,14 @@ async def sign_tx(tx: SignTx, root: bip32.HDNode): write_uint32(tx_ser.serialized_tx, tx.lock_time) if tx.overwintered: write_uint32(tx_ser.serialized_tx, tx.expiry) # expiryHeight - write_varint(tx_ser.serialized_tx, 0) # nJoinSplit + write_varint(tx_ser.serialized_tx, 0) # nJoinSplit await request_tx_finish(tx_req) -async def get_prevtx_output_value(coin: CoinInfo, tx_req: TxRequest, prev_hash: bytes, prev_index: int) -> int: +async def get_prevtx_output_value( + coin: CoinInfo, tx_req: TxRequest, prev_hash: bytes, prev_index: int +) -> int: total_out = 0 # sum of output amounts # STAGE_REQUEST_2_PREV_META @@ -407,9 +438,9 @@ async def get_prevtx_output_value(coin: CoinInfo, tx_req: TxRequest, prev_hash: if tx.overwintered: write_uint32(txh, tx.version | OVERWINTERED) # nVersion | fOverwintered - write_uint32(txh, coin.version_group_id) # nVersionGroupId + write_uint32(txh, coin.version_group_id) # nVersionGroupId else: - write_uint32(txh, tx.version) # nVersion + write_uint32(txh, tx.version) # nVersion write_varint(txh, tx.inputs_cnt) @@ -440,8 +471,7 @@ async def get_prevtx_output_value(coin: CoinInfo, tx_req: TxRequest, prev_hash: ofs += len(data) if get_tx_hash(txh, double=coin.sign_hash_double, reverse=True) != prev_hash: - raise SigningError(FailureType.ProcessError, - 'Encountered invalid prev_hash') + raise SigningError(FailureType.ProcessError, "Encountered invalid prev_hash") return total_out @@ -463,7 +493,7 @@ def get_tx_header(coin: CoinInfo, tx: SignTx, segwit: bool = False): w_txi = bytearray() if tx.overwintered: write_uint32(w_txi, tx.version | OVERWINTERED) # nVersion | fOverwintered - write_uint32(w_txi, coin.version_group_id) # nVersionGroupId + write_uint32(w_txi, coin.version_group_id) # nVersionGroupId else: write_uint32(w_txi, tx.version) # nVersion if segwit: @@ -482,33 +512,36 @@ def output_derive_script(o: TxOutputType, coin: CoinInfo, root: bip32.HDNode) -> if o.script_type == OutputScriptType.PAYTOOPRETURN: # op_return output if o.amount != 0: - raise SigningError(FailureType.DataError, - 'OP_RETURN output with non-zero amount') + raise SigningError( + FailureType.DataError, "OP_RETURN output with non-zero amount" + ) return output_script_paytoopreturn(o.op_return_data) if o.address_n: # change output if o.address: - raise SigningError(FailureType.DataError, 'Address in change output') + raise SigningError(FailureType.DataError, "Address in change output") o.address = get_address_for_change(o, coin, root) else: if not o.address: - raise SigningError(FailureType.DataError, 'Missing address') + raise SigningError(FailureType.DataError, "Missing address") if coin.bech32_prefix and o.address.startswith(coin.bech32_prefix): # p2wpkh or p2wsh witprog = decode_bech32_address(coin.bech32_prefix, o.address) return output_script_native_p2wpkh_or_p2wsh(witprog) - if coin.cashaddr_prefix is not None and o.address.startswith(coin.cashaddr_prefix + ':'): - prefix, addr = o.address.split(':') + if coin.cashaddr_prefix is not None and o.address.startswith( + coin.cashaddr_prefix + ":" + ): + prefix, addr = o.address.split(":") version, data = cashaddr.decode(prefix, addr) if version == cashaddr.ADDRESS_TYPE_P2KH: version = coin.address_type elif version == cashaddr.ADDRESS_TYPE_P2SH: version = coin.address_type_p2sh else: - raise ValueError('Unknown cashaddr address type') + raise ValueError("Unknown cashaddr address type") raw_address = bytes([version]) + data else: raw_address = base58.decode_check(o.address, coin.b58_hash) @@ -518,7 +551,9 @@ def output_derive_script(o: TxOutputType, coin: CoinInfo, root: bip32.HDNode) -> pubkeyhash = address_type.strip(coin.address_type, raw_address) script = output_script_p2pkh(pubkeyhash) if coin.bip115: - script += script_replay_protection_bip115(o.block_hash_bip115, o.block_height_bip115) + script += script_replay_protection_bip115( + o.block_hash_bip115, o.block_height_bip115 + ) return script elif address_type.check(coin.address_type_p2sh, raw_address): @@ -526,10 +561,12 @@ def output_derive_script(o: TxOutputType, coin: CoinInfo, root: bip32.HDNode) -> scripthash = address_type.strip(coin.address_type_p2sh, raw_address) script = output_script_p2sh(scripthash) if coin.bip115: - script += script_replay_protection_bip115(o.block_hash_bip115, o.block_height_bip115) + script += script_replay_protection_bip115( + o.block_hash_bip115, o.block_height_bip115 + ) return script - raise SigningError(FailureType.DataError, 'Invalid address type') + raise SigningError(FailureType.DataError, "Invalid address type") def get_address_for_change(o: TxOutputType, coin: CoinInfo, root: bip32.HDNode): @@ -542,33 +579,40 @@ def get_address_for_change(o: TxOutputType, coin: CoinInfo, root: bip32.HDNode): elif o.script_type == OutputScriptType.PAYTOP2SHWITNESS: input_script_type = InputScriptType.SPENDP2SHWITNESS else: - raise SigningError(FailureType.DataError, 'Invalid script type') - return get_address(input_script_type, coin, node_derive(root, o.address_n), o.multisig) + raise SigningError(FailureType.DataError, "Invalid script type") + return get_address( + input_script_type, coin, node_derive(root, o.address_n), o.multisig + ) def output_is_change(o: TxOutputType, wallet_path: list, segwit_in: int) -> bool: - is_segwit = (o.script_type == OutputScriptType.PAYTOWITNESS or - o.script_type == OutputScriptType.PAYTOP2SHWITNESS) + is_segwit = ( + o.script_type == OutputScriptType.PAYTOWITNESS + or o.script_type == OutputScriptType.PAYTOP2SHWITNESS + ) if is_segwit and o.amount > segwit_in: # if the output is segwit, make sure it doesn't spend more than what the # segwit inputs paid. this is to prevent user being tricked into # creating ANYONECANSPEND outputs before full segwit activation. return False - return (wallet_path is not None and - wallet_path == o.address_n[:-_BIP32_WALLET_DEPTH] and - o.address_n[-2] <= _BIP32_CHANGE_CHAIN and - o.address_n[-1] <= _BIP32_MAX_LAST_ELEMENT) + return ( + wallet_path is not None + and wallet_path == o.address_n[:-_BIP32_WALLET_DEPTH] + and o.address_n[-2] <= _BIP32_CHANGE_CHAIN + and o.address_n[-1] <= _BIP32_MAX_LAST_ELEMENT + ) # Tx Inputs # === -def input_derive_script(coin: CoinInfo, i: TxInputType, pubkey: bytes, signature: bytes=None) -> bytes: +def input_derive_script( + coin: CoinInfo, i: TxInputType, pubkey: bytes, signature: bytes = None +) -> bytes: if i.script_type == InputScriptType.SPENDADDRESS: # p2pkh or p2sh - return input_script_p2pkh_or_p2sh( - pubkey, signature, get_hash_type(coin)) + return input_script_p2pkh_or_p2sh(pubkey, signature, get_hash_type(coin)) if i.script_type == InputScriptType.SPENDP2SHWITNESS: # p2wpkh or p2wsh using p2sh @@ -591,10 +635,11 @@ def input_derive_script(coin: CoinInfo, i: TxInputType, pubkey: bytes, signature # p2sh multisig signature_index = multisig_pubkey_index(i.multisig, pubkey) return input_script_multisig( - i.multisig, signature, signature_index, get_hash_type(coin)) + i.multisig, signature, signature_index, get_hash_type(coin) + ) else: - raise SigningError(FailureType.ProcessError, 'Invalid script type') + raise SigningError(FailureType.ProcessError, "Invalid script type") def input_extract_wallet_path(txi: TxInputType, wallet_path: list) -> list: @@ -615,8 +660,9 @@ def input_check_wallet_path(txi: TxInputType, wallet_path: list) -> list: return # there was a mismatch in Phase 1, ignore it now address_n = txi.address_n[:-_BIP32_WALLET_DEPTH] if wallet_path != address_n: - raise SigningError(FailureType.ProcessError, - 'Transaction has changed during signing') + raise SigningError( + FailureType.ProcessError, "Transaction has changed during signing" + ) def node_derive(root: bip32.HDNode, address_n: list) -> bip32.HDNode: @@ -630,7 +676,9 @@ def address_n_matches_coin(address_n: list, coin: CoinInfo) -> bool: return True # path is too short if address_n[0] not in (44 | 0x80000000, 49 | 0x80000000, 84 | 0x80000000): return True # path is not BIP44/49/84 - return address_n[1] == (coin.slip44 | 0x80000000) # check whether coin_type matches slip44 value + return address_n[1] == ( + coin.slip44 | 0x80000000 + ) # check whether coin_type matches slip44 value def ecdsa_sign(node: bip32.HDNode, digest: bytes) -> bytes: @@ -640,10 +688,8 @@ def ecdsa_sign(node: bip32.HDNode, digest: bytes) -> bytes: def is_change( - txo: TxOutputType, - wallet_path: list, - segwit_in: int, - multifp: MultisigFingerprint) -> bool: + txo: TxOutputType, wallet_path: list, segwit_in: int, multifp: MultisigFingerprint +) -> bool: if txo.multisig: if not multifp.matches(txo.multisig): return False diff --git a/src/apps/wallet/sign_tx/tx_weight_calculator.py b/src/apps/wallet/sign_tx/tx_weight_calculator.py index e36861496..2a1bb75eb 100644 --- a/src/apps/wallet/sign_tx/tx_weight_calculator.py +++ b/src/apps/wallet/sign_tx/tx_weight_calculator.py @@ -34,14 +34,14 @@ _TXSIZE_WITNESSSCRIPT = const(34) class TxWeightCalculator: - def __init__(self, inputs_count: int, outputs_count: int): self.inputs_count = inputs_count self.counter = 4 * ( - _TXSIZE_HEADER + - _TXSIZE_FOOTER + - self.ser_length_size(inputs_count) + - self.ser_length_size(outputs_count)) + _TXSIZE_HEADER + + _TXSIZE_FOOTER + + self.ser_length_size(inputs_count) + + self.ser_length_size(outputs_count) + ) self.segwit = False def add_witness_header(self): @@ -53,26 +53,31 @@ class TxWeightCalculator: def add_input(self, i: TxInputType): if i.multisig: - multisig_script_size = ( - _TXSIZE_MULTISIGSCRIPT + - len(i.multisig.pubkeys) * (1 + _TXSIZE_PUBKEY)) + multisig_script_size = _TXSIZE_MULTISIGSCRIPT + len(i.multisig.pubkeys) * ( + 1 + _TXSIZE_PUBKEY + ) input_script_size = ( - 1 + # the OP_FALSE bug in multisig - i.multisig.m * (1 + _TXSIZE_SIGNATURE) + - self.op_push_size(multisig_script_size) + - multisig_script_size) + 1 + + i.multisig.m * (1 + _TXSIZE_SIGNATURE) # the OP_FALSE bug in multisig + + self.op_push_size(multisig_script_size) + + multisig_script_size + ) else: input_script_size = 1 + _TXSIZE_SIGNATURE + 1 + _TXSIZE_PUBKEY self.counter += 4 * _TXSIZE_INPUT - if (i.script_type == InputScriptType.SPENDADDRESS or - i.script_type == InputScriptType.SPENDMULTISIG): + if ( + i.script_type == InputScriptType.SPENDADDRESS + or i.script_type == InputScriptType.SPENDMULTISIG + ): input_script_size += self.ser_length_size(input_script_size) self.counter += 4 * input_script_size - elif (i.script_type == InputScriptType.SPENDWITNESS or - i.script_type == InputScriptType.SPENDP2SHWITNESS): + elif ( + i.script_type == InputScriptType.SPENDWITNESS + or i.script_type == InputScriptType.SPENDP2SHWITNESS + ): self.add_witness_header() if i.script_type == InputScriptType.SPENDP2SHWITNESS: if i.multisig: diff --git a/src/apps/wallet/sign_tx/writers.py b/src/apps/wallet/sign_tx/writers.py index 192abde43..16afb2538 100644 --- a/src/apps/wallet/sign_tx/writers.py +++ b/src/apps/wallet/sign_tx/writers.py @@ -130,7 +130,7 @@ def bytearray_with_cap(cap: int) -> bytearray: # === -def get_tx_hash(w, double: bool=False, reverse: bool=False) -> bytes: +def get_tx_hash(w, double: bool = False, reverse: bool = False) -> bytes: d = w.get_digest() if double: d = sha256(d).digest() diff --git a/src/apps/wallet/verify_message.py b/src/apps/wallet/verify_message.py index 766ef8a09..48fac8299 100644 --- a/src/apps/wallet/verify_message.py +++ b/src/apps/wallet/verify_message.py @@ -21,7 +21,7 @@ async def verify_message(ctx, msg): message = msg.message address = msg.address signature = msg.signature - coin_name = msg.coin_name or 'Bitcoin' + coin_name = msg.coin_name or "Bitcoin" coin = coins.by_name(coin_name) digest = message_digest(coin, message) @@ -37,12 +37,12 @@ async def verify_message(ctx, msg): script_type = SPENDWITNESS # native segwit signature = bytes([signature[0] - 8]) + signature[1:] else: - raise wire.ProcessError('Invalid signature') + raise wire.ProcessError("Invalid signature") pubkey = secp256k1.verify_recover(signature, digest) if not pubkey: - raise wire.ProcessError('Invalid signature') + raise wire.ProcessError("Invalid signature") if script_type == SPENDADDRESS: addr = address_pkh(pubkey, coin) @@ -53,21 +53,21 @@ async def verify_message(ctx, msg): elif script_type == SPENDWITNESS: addr = address_p2wpkh(pubkey, coin.bech32_prefix) else: - raise wire.ProcessError('Invalid signature') + raise wire.ProcessError("Invalid signature") if addr != address: - raise wire.ProcessError('Invalid signature') + raise wire.ProcessError("Invalid signature") await require_confirm_verify_message(ctx, address_short(coin, address), message) - return Success(message='Message verified') + return Success(message="Message verified") async def require_confirm_verify_message(ctx, address, message): - text = Text('Confirm address') + text = Text("Confirm address") text.mono(*split_address(address)) await require_confirm(ctx, text) - text = Text('Verify message') + text = Text("Verify message") text.normal(*split_message(message)) await require_confirm(ctx, text) diff --git a/src/boot.py b/src/boot.py index fa59913a3..ade161059 100644 --- a/src/boot.py +++ b/src/boot.py @@ -8,7 +8,7 @@ async def bootscreen(): while True: try: if not config.has_pin(): - config.unlock(pin_to_int(''), show_pin_timeout) + config.unlock(pin_to_int(""), show_pin_timeout) return await lockscreen() label = None @@ -17,7 +17,7 @@ async def bootscreen(): if config.unlock(pin_to_int(pin), show_pin_timeout): return else: - label = 'Wrong PIN, enter again' + label = "Wrong PIN, enter again" except: # noqa: E722 pass @@ -28,9 +28,9 @@ async def lockscreen(): label = storage.get_label() image = storage.get_homescreen() if not label: - label = 'My TREZOR' + label = "My TREZOR" if not image: - image = res.load('apps/homescreen/res/bg.toif') + image = res.load("apps/homescreen/res/bg.toif") await ui.backlight_slide(ui.BACKLIGHT_DIM) @@ -40,9 +40,11 @@ async def lockscreen(): ui.display.bar_radius(40, 100, 160, 40, ui.TITLE_GREY, ui.BG, 4) ui.display.bar_radius(42, 102, 156, 36, ui.BG, ui.TITLE_GREY, 4) - ui.display.text_center(ui.WIDTH // 2, 128, 'Locked', ui.BOLD, ui.TITLE_GREY, ui.BG) + ui.display.text_center(ui.WIDTH // 2, 128, "Locked", ui.BOLD, ui.TITLE_GREY, ui.BG) - ui.display.text_center(ui.WIDTH // 2 + 10, 220, 'Tap to unlock', ui.BOLD, ui.TITLE_GREY, ui.BG) + ui.display.text_center( + ui.WIDTH // 2 + 10, 220, "Tap to unlock", ui.BOLD, ui.TITLE_GREY, ui.BG + ) ui.display.icon(45, 202, res.load(ui.ICON_CLICK), ui.TITLE_GREY, ui.BG) await ui.backlight_slide(ui.BACKLIGHT_NORMAL) diff --git a/src/main.py b/src/main.py index a78d76086..8b61f9967 100644 --- a/src/main.py +++ b/src/main.py @@ -15,6 +15,7 @@ import apps.wallet import apps.ethereum import apps.lisk import apps.nem + if __debug__: import apps.debug else: @@ -43,5 +44,6 @@ utils.set_mode_unprivileged() # run main event loop and specify which screen is the default from apps.homescreen.homescreen import homescreen + workflow.startdefault(homescreen) loop.run() diff --git a/src/protobuf.py b/src/protobuf.py index a7d03a41a..92fc118bd 100644 --- a/src/protobuf.py +++ b/src/protobuf.py @@ -70,6 +70,7 @@ async def dump_uvarint(writer, n): # But this is harder in Python because we don't natively know the bit size of the number. # So we have to branch on whether the number is negative. + def sint_to_uint(sint): res = sint << 1 if sint < 0: @@ -114,11 +115,10 @@ class MessageType: setattr(self, kw, kwargs[kw]) def __eq__(self, rhs): - return (self.__class__ is rhs.__class__ and - self.__dict__ == rhs.__dict__) + return self.__class__ is rhs.__class__ and self.__dict__ == rhs.__dict__ def __repr__(self): - return '<%s>' % self.__class__.__name__ + return "<%s>" % self.__class__.__name__ class LimitedReader: @@ -191,7 +191,7 @@ async def load_message(reader, msg_type): elif ftype is UnicodeType: fvalue = bytearray(ivalue) await reader.areadinto(fvalue) - fvalue = str(fvalue, 'utf8') + fvalue = str(fvalue, "utf8") elif issubclass(ftype, MessageType): fvalue = await load_message(LimitedReader(reader, ivalue), ftype) else: @@ -247,7 +247,7 @@ async def dump_message(writer, msg): await writer.awrite(svalue) elif ftype is UnicodeType: - bvalue = bytes(svalue, 'utf8') + bvalue = bytes(svalue, "utf8") await dump_uvarint(writer, len(bvalue)) await writer.awrite(bvalue) diff --git a/src/trezor/crypto/aes.py b/src/trezor/crypto/aes.py index 46616ff13..8b9cae112 100644 --- a/src/trezor/crypto/aes.py +++ b/src/trezor/crypto/aes.py @@ -2,70 +2,70 @@ from trezorcrypto import AES def AES_ECB_Encrypt(key: bytes) -> AES: - ''' + """ Create AES encryption context in ECB mode - ''' + """ return AES(AES.ECB | AES.Encrypt, key) def AES_ECB_Decrypt(key: bytes) -> AES: - ''' + """ Create AES decryption context in ECB mode - ''' + """ return AES(AES.ECB | AES.Decrypt, key) def AES_CBC_Encrypt(key: bytes, iv: bytes) -> AES: - ''' + """ Create AES encryption context in CBC mode - ''' + """ return AES(AES.CBC | AES.Encrypt, key, iv) def AES_CBC_Decrypt(key: bytes, iv: bytes) -> AES: - ''' + """ Create AES decryption context in CBC mode - ''' + """ return AES(AES.CBC | AES.Decrypt, key, iv) def AES_CFB_Encrypt(key: bytes, iv: bytes) -> AES: - ''' + """ Create AES encryption context in CFB mode - ''' + """ return AES(AES.CFB | AES.Encrypt, key, iv) def AES_CFB_Decrypt(key: bytes, iv: bytes) -> AES: - ''' + """ Create AES decryption context in CFB mode - ''' + """ return AES(AES.CFB | AES.Decrypt, key, iv) def AES_OFB_Encrypt(key: bytes, iv: bytes) -> AES: - ''' + """ Create AES encryption context in OFB mode - ''' + """ return AES(AES.OFB | AES.Encrypt, key, iv) def AES_OFB_Decrypt(key: bytes, iv: bytes) -> AES: - ''' + """ Create AES decryption context in OFB mode - ''' + """ return AES(AES.OFB | AES.Decrypt, key, iv) def AES_CTR_Encrypt(key: bytes) -> AES: - ''' + """ Create AES encryption context in CTR mode - ''' + """ return AES(AES.CTR | AES.Encrypt, key) def AES_CTR_Decrypt(key: bytes) -> AES: - ''' + """ Create AES decryption context in CTR mode - ''' + """ return AES(AES.CTR | AES.Decrypt, key) diff --git a/src/trezor/crypto/base32.py b/src/trezor/crypto/base32.py index b70b4a9d8..5fdf7afec 100644 --- a/src/trezor/crypto/base32.py +++ b/src/trezor/crypto/base32.py @@ -5,7 +5,7 @@ from ubinascii import unhexlify from ustruct import unpack -_b32alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567' +_b32alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" _b32tab = [ord(c) for c in _b32alphabet] _b32rev = dict([(ord(v), k) for k, v in enumerate(_b32alphabet)]) @@ -24,27 +24,30 @@ def encode(s: bytes) -> str: # leftover bit of c1 and tack it onto c2. Then we take the 2 leftover # bits of c2 and tack them onto c3. The shifts and masks are intended # to give us values of exactly 5 bits in width. - c1, c2, c3 = unpack('!HHB', s[i * 5:(i + 1) * 5]) + c1, c2, c3 = unpack("!HHB", s[i * 5 : (i + 1) * 5]) c2 += (c1 & 1) << 16 # 17 bits wide - c3 += (c2 & 3) << 8 # 10 bits wide - encoded += bytes([_b32tab[c1 >> 11], # bits 1 - 5 - _b32tab[(c1 >> 6) & 0x1f], # bits 6 - 10 - _b32tab[(c1 >> 1) & 0x1f], # bits 11 - 15 - _b32tab[c2 >> 12], # bits 16 - 20 (1 - 5) - _b32tab[(c2 >> 7) & 0x1f], # bits 21 - 25 (6 - 10) - _b32tab[(c2 >> 2) & 0x1f], # bits 26 - 30 (11 - 15) - _b32tab[c3 >> 5], # bits 31 - 35 (1 - 5) - _b32tab[c3 & 0x1f], # bits 36 - 40 (1 - 5) - ]) + c3 += (c2 & 3) << 8 # 10 bits wide + encoded += bytes( + [ + _b32tab[c1 >> 11], # bits 1 - 5 + _b32tab[(c1 >> 6) & 0x1f], # bits 6 - 10 + _b32tab[(c1 >> 1) & 0x1f], # bits 11 - 15 + _b32tab[c2 >> 12], # bits 16 - 20 (1 - 5) + _b32tab[(c2 >> 7) & 0x1f], # bits 21 - 25 (6 - 10) + _b32tab[(c2 >> 2) & 0x1f], # bits 26 - 30 (11 - 15) + _b32tab[c3 >> 5], # bits 31 - 35 (1 - 5) + _b32tab[c3 & 0x1f], # bits 36 - 40 (1 - 5) + ] + ) # Adjust for any leftover partial quanta if leftover == 1: - encoded = encoded[:-6] + b'======' + encoded = encoded[:-6] + b"======" elif leftover == 2: - encoded = encoded[:-4] + b'====' + encoded = encoded[:-4] + b"====" elif leftover == 3: - encoded = encoded[:-3] + b'===' + encoded = encoded[:-3] + b"===" elif leftover == 4: - encoded = encoded[:-1] + b'=' + encoded = encoded[:-1] + b"=" return bytes(encoded).decode() @@ -53,11 +56,11 @@ def decode(s: str) -> bytes: s = s.encode() quanta, leftover = divmod(len(s), 8) if leftover: - raise ValueError('Incorrect padding') + raise ValueError("Incorrect padding") # Strip off pad characters from the right. We need to count the pad # characters because this will tell us how many null bytes to remove from # the end of the decoded string. - padchars = s.find(b'=') + padchars = s.find(b"=") if padchars > 0: padchars = len(s) - padchars s = s[:-padchars] @@ -71,17 +74,17 @@ def decode(s: str) -> bytes: for c in s: val = _b32rev.get(c) if val is None: - raise ValueError('Non-base32 digit found') + raise ValueError("Non-base32 digit found") acc += _b32rev[c] << shift shift -= 5 if shift < 0: - parts.append(unhexlify(('%010x' % acc).encode())) + parts.append(unhexlify(("%010x" % acc).encode())) acc = 0 shift = 35 # Process the last, partial quanta - last = unhexlify(bytes('%010x' % acc, "ascii")) + last = unhexlify(bytes("%010x" % acc, "ascii")) if padchars == 0: - last = b'' # No characters + last = b"" # No characters elif padchars == 1: last = last[:-1] elif padchars == 3: @@ -91,6 +94,6 @@ def decode(s: str) -> bytes: elif padchars == 6: last = last[:-4] else: - raise ValueError('Incorrect padding') + raise ValueError("Incorrect padding") parts.append(last) - return b''.join(parts) + return b"".join(parts) diff --git a/src/trezor/crypto/base58.py b/src/trezor/crypto/base58.py index f4c36cd0b..9edadd8d3 100644 --- a/src/trezor/crypto/base58.py +++ b/src/trezor/crypto/base58.py @@ -14,15 +14,15 @@ # # 58 character alphabet used -_alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' +_alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" def encode(data: bytes) -> str: - ''' + """ Convert bytes to base58 encoded string. - ''' + """ origlen = len(data) - data = data.lstrip(b'\0') + data = data.lstrip(b"\0") newlen = len(data) p, acc = 1, 0 @@ -30,18 +30,18 @@ def encode(data: bytes) -> str: acc += p * c p = p << 8 - result = '' + result = "" while acc > 0: acc, mod = divmod(acc, 58) result += _alphabet[mod] - return ''.join((c for c in reversed(result + _alphabet[0] * (origlen - newlen)))) + return "".join((c for c in reversed(result + _alphabet[0] * (origlen - newlen)))) def decode(string: str) -> bytes: - ''' + """ Convert base58 encoded string to bytes. - ''' + """ origlen = len(string) string = string.lstrip(_alphabet[0]) newlen = len(string) @@ -61,28 +61,32 @@ def decode(string: str) -> bytes: def sha256d_32(data: bytes) -> bytes: from .hashlib import sha256 + return sha256(sha256(data).digest()).digest()[:4] + def groestl512d_32(data: bytes) -> bytes: from .hashlib import groestl512 + return groestl512(groestl512(data).digest()).digest()[:4] + def encode_check(data: bytes, digestfunc=sha256d_32) -> str: - ''' + """ Convert bytes to base58 encoded string, append checksum. - ''' + """ return encode(data + digestfunc(data)) def decode_check(string: str, digestfunc=sha256d_32) -> bytes: - ''' + """ Convert base58 encoded string to bytes and verify checksum. - ''' + """ result = decode(string) - digestlen = len(digestfunc(b'')) + digestlen = len(digestfunc(b"")) result, check = result[:-digestlen], result[-digestlen:] if check != digestfunc(result): - raise ValueError('Invalid checksum') + raise ValueError("Invalid checksum") return result diff --git a/src/trezor/crypto/bech32.py b/src/trezor/crypto/bech32.py index 68f246874..e2c3d21ca 100644 --- a/src/trezor/crypto/bech32.py +++ b/src/trezor/crypto/bech32.py @@ -56,22 +56,23 @@ def bech32_create_checksum(hrp, data): def bech32_encode(hrp, data): """Compute a Bech32 string given HRP and data values.""" combined = data + bech32_create_checksum(hrp, data) - return hrp + '1' + ''.join([CHARSET[d] for d in combined]) + return hrp + "1" + "".join([CHARSET[d] for d in combined]) def bech32_decode(bech): """Validate a Bech32 string, and determine HRP and data.""" - if ((any(ord(x) < 33 or ord(x) > 126 for x in bech)) or - (bech.lower() != bech and bech.upper() != bech)): + if (any(ord(x) < 33 or ord(x) > 126 for x in bech)) or ( + bech.lower() != bech and bech.upper() != bech + ): return (None, None) bech = bech.lower() - pos = bech.rfind('1') + pos = bech.rfind("1") if pos < 1 or pos + 7 > len(bech) or len(bech) > 90: return (None, None) - if not all(x in CHARSET for x in bech[pos + 1:]): + if not all(x in CHARSET for x in bech[pos + 1 :]): return (None, None) hrp = bech[:pos] - data = [CHARSET.find(x) for x in bech[pos + 1:]] + data = [CHARSET.find(x) for x in bech[pos + 1 :]] if not bech32_verify_checksum(hrp, data): return (None, None) return (hrp, data[:-6]) diff --git a/src/trezor/crypto/cashaddr.py b/src/trezor/crypto/cashaddr.py index ffaede67b..c133fe2a7 100644 --- a/src/trezor/crypto/cashaddr.py +++ b/src/trezor/crypto/cashaddr.py @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l' +CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" ADDRESS_TYPE_P2KH = 0 ADDRESS_TYPE_P2SH = 8 @@ -60,7 +60,7 @@ def b32decode(inputs): def b32encode(inputs): - out = '' + out = "" for char_code in inputs: out += CHARSET[char_code] return out @@ -92,13 +92,13 @@ def encode(prefix, version, payload): payload = bytes([version]) + payload payload = convertbits(payload, 8, 5) checksum = calculate_checksum(prefix, payload) - return prefix + ':' + b32encode(payload + checksum) + return prefix + ":" + b32encode(payload + checksum) def decode(prefix, addr): addr = addr.lower() decoded = b32decode(addr) if not verify_checksum(prefix, decoded): - raise ValueError('Bad cashaddr checksum') + raise ValueError("Bad cashaddr checksum") data = bytes(convertbits(decoded, 5, 8)) return data[0], data[1:-6] diff --git a/src/trezor/crypto/der.py b/src/trezor/crypto/der.py index a6e1bc618..c64b4b973 100644 --- a/src/trezor/crypto/der.py +++ b/src/trezor/crypto/der.py @@ -1,4 +1,3 @@ - def encode_length(l: int) -> bytes: if l < 0x80: return bytes([l]) @@ -11,14 +10,14 @@ def encode_length(l: int) -> bytes: def encode_int(i: bytes) -> bytes: - i = i.lstrip(b'\x00') + i = i.lstrip(b"\x00") if i[0] >= 0x80: - i = b'\x00' + i - return b'\x02' + encode_length(len(i)) + i + i = b"\x00" + i + return b"\x02" + encode_length(len(i)) + i def encode_seq(seq: tuple) -> bytes: - res = b'' + res = b"" for i in seq: res += encode_int(i) - return b'\x30' + encode_length(len(res)) + res + return b"\x30" + encode_length(len(res)) + res diff --git a/src/trezor/crypto/hmac.py b/src/trezor/crypto/hmac.py index 005013f3f..6f16fffbe 100644 --- a/src/trezor/crypto/hmac.py +++ b/src/trezor/crypto/hmac.py @@ -1,6 +1,4 @@ - class Hmac: - def __init__(self, key, msg, digestmod): self.digestmod = digestmod self.inner = digestmod() @@ -15,15 +13,15 @@ class Hmac: self.update(msg) def update(self, msg: bytes) -> None: - ''' + """ Update the context with data. - ''' + """ self.inner.update(msg) def digest(self) -> bytes: - ''' + """ Returns the digest of processed data. - ''' + """ outer = self.digestmod() outer.update(bytes((x ^ 0x5C) for x in self.key)) outer.update(self.inner.digest()) @@ -31,7 +29,7 @@ class Hmac: def new(key, msg, digestmod) -> Hmac: - ''' + """ Creates a HMAC context object. - ''' + """ return Hmac(key, msg, digestmod) diff --git a/src/trezor/crypto/rlp.py b/src/trezor/crypto/rlp.py index 0745bca0a..b052241a3 100644 --- a/src/trezor/crypto/rlp.py +++ b/src/trezor/crypto/rlp.py @@ -1,7 +1,6 @@ - def int_to_bytes(x: int) -> bytes: if x == 0: - return b'' + return b"" r = bytearray() while x: r.append(x % 256) @@ -17,7 +16,7 @@ def encode_length(l: int, is_list: bool) -> bytes: bl = int_to_bytes(l) return bytes([len(bl) + offset + 55]) + bl else: - raise ValueError('Input too long') + raise ValueError("Input too long") def encode(data, include_length=True) -> bytes: @@ -31,7 +30,7 @@ def encode(data, include_length=True) -> bytes: else: return encode_length(len(data), is_list=False) + data elif isinstance(data, list): - output = b'' + output = b"" for item in data: output += encode(item) if include_length: @@ -39,7 +38,7 @@ def encode(data, include_length=True) -> bytes: else: return output else: - raise TypeError('Invalid input of type ' + str(type(data))) + raise TypeError("Invalid input of type " + str(type(data))) def field_length(length: int, first_byte: bytearray) -> int: diff --git a/src/trezor/log.py b/src/trezor/log.py index 1c5f47c07..a1ba47685 100644 --- a/src/trezor/log.py +++ b/src/trezor/log.py @@ -10,11 +10,11 @@ ERROR = const(40) CRITICAL = const(50) _leveldict = { - DEBUG: ('DEBUG', '32'), - INFO: ('INFO', '36'), - WARNING: ('WARNING', '33'), - ERROR: ('ERROR', '31'), - CRITICAL: ('CRITICAL', '1;31'), + DEBUG: ("DEBUG", "32"), + INFO: ("INFO", "36"), + WARNING: ("WARNING", "33"), + ERROR: ("ERROR", "31"), + CRITICAL: ("CRITICAL", "1;31"), } level = DEBUG @@ -24,9 +24,14 @@ color = True def _log(name, mlevel, msg, *args): if __debug__ and mlevel >= level: if color: - fmt = '%d \x1b[35m%s\x1b[0m \x1b[' + _leveldict[mlevel][1] + 'm%s\x1b[0m ' + msg + fmt = ( + "%d \x1b[35m%s\x1b[0m \x1b[" + + _leveldict[mlevel][1] + + "m%s\x1b[0m " + + msg + ) else: - fmt = '%d %s %s ' + msg + fmt = "%d %s %s " + msg print(fmt % ((utime.ticks_us(), name, _leveldict[mlevel][0]) + args)) @@ -47,7 +52,7 @@ def error(name, msg, *args): def exception(name, exc): - _log(name, ERROR, 'exception:') + _log(name, ERROR, "exception:") sys.print_exception(exc) diff --git a/src/trezor/loop.py b/src/trezor/loop.py index c1dc6c450..bc697bc15 100644 --- a/src/trezor/loop.py +++ b/src/trezor/loop.py @@ -1,11 +1,11 @@ -''' +""" Implements an event loop with cooperative multitasking and async I/O. Tasks in the form of python coroutines (either plain generators or `async` functions) are stepped through until completion, and can get asynchronously blocked by `yield`ing or `await`ing a syscall. See `schedule`, `run`, and syscalls `sleep`, `wait`, `signal` and `spawn`. -''' +""" import utime import utimeq @@ -22,16 +22,17 @@ _paused = {} if __debug__: # for performance stats import array + log_delay_pos = 0 log_delay_rb_len = const(10) - log_delay_rb = array.array('i', [0] * log_delay_rb_len) + log_delay_rb = array.array("i", [0] * log_delay_rb_len) def schedule(task, value=None, deadline=None): - ''' + """ Schedule task to be executed with `value` on given `deadline` (in microseconds). Does not start the event loop itself, see `run`. - ''' + """ if deadline is None: deadline = utime.ticks_us() _queue.push(deadline, task, value) @@ -52,12 +53,12 @@ def close(task): def run(): - ''' + """ Loop forever, stepping through scheduled tasks and awaiting I/O events inbetween. Use `schedule` first to add a coroutine to the task queue. Tasks yield back to the scheduler on any I/O, usually by calling `await` on a `Syscall`. - ''' + """ if __debug__: global log_delay_pos @@ -98,7 +99,7 @@ def _step(task, value): result = task.send(value) except StopIteration as e: if __debug__: - log.debug(__name__, 'finish: %s', task) + log.debug(__name__, "finish: %s", task) except Exception as e: if __debug__: log.exception(__name__, e) @@ -109,16 +110,16 @@ def _step(task, value): schedule(task) else: if __debug__: - log.error(__name__, 'unknown syscall: %s', result) + log.error(__name__, "unknown syscall: %s", result) if after_step_hook: after_step_hook() class Syscall: - ''' + """ When tasks want to perform any I/O, or do any sort of communication with the scheduler, they do so through instances of a class derived from `Syscall`. - ''' + """ def __iter__(self): # support `yield from` or `await` on syscalls @@ -126,7 +127,7 @@ class Syscall: class sleep(Syscall): - ''' + """ Pause current task and resume it after given delay. Although the delay is given in microseconds, sub-millisecond precision is not guaranteed. Result value is the calculated deadline. @@ -135,7 +136,7 @@ class sleep(Syscall): >>> planned = await loop.sleep(1000 * 1000) # sleep for 1ms >>> print('missed by %d us', utime.ticks_diff(utime.ticks_us(), planned)) - ''' + """ def __init__(self, delay_us): self.delay_us = delay_us @@ -146,7 +147,7 @@ class sleep(Syscall): class wait(Syscall): - ''' + """ Pause current task, and resume only after a message on `msg_iface` is received. Messages are received either from an USB interface, or the touch display. Result value a tuple of message values. @@ -155,7 +156,7 @@ class wait(Syscall): >>> hid_report, = await loop.wait(0xABCD) # await USB HID report >>> event, x, y = await loop.wait(io.TOUCH) # await touch event - ''' + """ def __init__(self, msg_iface): self.msg_iface = msg_iface @@ -168,7 +169,7 @@ _NO_VALUE = () class signal(Syscall): - ''' + """ Pause current task, and let other running task to resume it later with a result value or an exception. @@ -181,7 +182,7 @@ class signal(Syscall): >>> # in task #2: >>> signal.send('hello from task #2') >>> # prints in the next iteration of the event loop - ''' + """ def __init__(self): self.value = _NO_VALUE @@ -210,7 +211,7 @@ class signal(Syscall): class spawn(Syscall): - ''' + """ Execute one or more children tasks and wait until one of them exits. Return value of `spawn` is the return value of task that triggered the completion. By default, `spawn` returns after the first child completes, and @@ -232,7 +233,7 @@ class spawn(Syscall): Note: You should not directly `yield` a `spawn` instance, see logic in `spawn.__iter__` for explanation. Always use `await`. - ''' + """ def __init__(self, *children, exit_others=True): self.children = children @@ -281,7 +282,6 @@ class spawn(Syscall): class put(Syscall): - def __init__(self, ch, value=None): self.ch = ch self.value = value @@ -295,7 +295,6 @@ class put(Syscall): class take(Syscall): - def __init__(self, ch): self.ch = ch @@ -308,7 +307,6 @@ class take(Syscall): class chan: - def __init__(self, id=None): self.id = id self.putters = [] diff --git a/src/trezor/pin.py b/src/trezor/pin.py index 69e426416..983df9a00 100644 --- a/src/trezor/pin.py +++ b/src/trezor/pin.py @@ -2,18 +2,38 @@ from trezor import ui def pin_to_int(pin: str) -> int: - return int('1' + pin) + return int("1" + pin) def show_pin_timeout(seconds: int, progress: int): if progress == 0: ui.display.bar(0, 0, ui.WIDTH, ui.HEIGHT, ui.BG) - ui.display.text_center(ui.WIDTH // 2, 37, 'Verifying PIN', ui.BOLD, ui.FG, ui.BG, ui.WIDTH) + ui.display.text_center( + ui.WIDTH // 2, 37, "Verifying PIN", ui.BOLD, ui.FG, ui.BG, ui.WIDTH + ) ui.display.loader(progress, 0, ui.FG, ui.BG) if seconds == 0: - ui.display.text_center(ui.WIDTH // 2, ui.HEIGHT - 22, 'Done', ui.BOLD, ui.FG, ui.BG, ui.WIDTH) + ui.display.text_center( + ui.WIDTH // 2, ui.HEIGHT - 22, "Done", ui.BOLD, ui.FG, ui.BG, ui.WIDTH + ) elif seconds == 1: - ui.display.text_center(ui.WIDTH // 2, ui.HEIGHT - 22, '1 second left', ui.BOLD, ui.FG, ui.BG, ui.WIDTH) + ui.display.text_center( + ui.WIDTH // 2, + ui.HEIGHT - 22, + "1 second left", + ui.BOLD, + ui.FG, + ui.BG, + ui.WIDTH, + ) else: - ui.display.text_center(ui.WIDTH // 2, ui.HEIGHT - 22, '%d seconds left' % seconds, ui.BOLD, ui.FG, ui.BG, ui.WIDTH) + ui.display.text_center( + ui.WIDTH // 2, + ui.HEIGHT - 22, + "%d seconds left" % seconds, + ui.BOLD, + ui.FG, + ui.BG, + ui.WIDTH, + ) ui.display.refresh() diff --git a/src/trezor/res/__init__.py b/src/trezor/res/__init__.py index 47028d20a..cc63ef5c8 100644 --- a/src/trezor/res/__init__.py +++ b/src/trezor/res/__init__.py @@ -5,16 +5,16 @@ except ImportError: def load(name): - ''' + """ Loads resource of a given name as bytes. - ''' + """ return resdata[name] def gettext(message): - ''' + """ Returns localized string. This function is aliased to _. - ''' + """ return message diff --git a/src/trezor/ui/button.py b/src/trezor/ui/button.py index 2e25cee88..d7d91fa4e 100644 --- a/src/trezor/ui/button.py +++ b/src/trezor/ui/button.py @@ -18,13 +18,12 @@ BORDER = const(4) # border size in pixels class Button(LazyWidget): - def __init__(self, area: tuple, content: str, style: dict = ui.BTN_KEY): self.area = area self.content = content - self.normal_style = style['normal'] or ui.BTN_KEY['normal'] - self.active_style = style['active'] or ui.BTN_KEY['active'] - self.disabled_style = style['disabled'] or ui.BTN_KEY['disabled'] + self.normal_style = style["normal"] or ui.BTN_KEY["normal"] + self.active_style = style["active"] or ui.BTN_KEY["active"] + self.disabled_style = style["disabled"] or ui.BTN_KEY["disabled"] self.state = BTN_INITIAL def enable(self): @@ -50,28 +49,24 @@ class Button(LazyWidget): self.render_content(s, ax, ay, aw, ah) def render_background(self, s, ax, ay, aw, ah): - radius = s['radius'] - bg_color = s['bg-color'] - border_color = s['border-color'] + radius = s["radius"] + bg_color = s["bg-color"] + border_color = s["border-color"] if border_color != bg_color: # render border and background on top of it - display.bar_radius(ax, ay, - aw, ah, - border_color, - ui.BG, - radius) - display.bar_radius(ax + BORDER, ay + BORDER, - aw - BORDER * 2, ah - BORDER * 2, - bg_color, - border_color, - radius) + display.bar_radius(ax, ay, aw, ah, border_color, ui.BG, radius) + display.bar_radius( + ax + BORDER, + ay + BORDER, + aw - BORDER * 2, + ah - BORDER * 2, + bg_color, + border_color, + radius, + ) else: # render only the background - display.bar_radius(ax, ay, - aw, ah, - bg_color, - ui.BG, - radius) + display.bar_radius(ax, ay, aw, ah, bg_color, ui.BG, radius) def render_content(self, s, ax, ay, aw, ah): c = self.content @@ -79,10 +74,10 @@ class Button(LazyWidget): ty = ay + ah // 2 + 8 if isinstance(c, str): display.text_center( - tx, ty, c, s['text-style'], s['fg-color'], s['bg-color']) + tx, ty, c, s["text-style"], s["fg-color"], s["bg-color"] + ) else: - display.icon( - tx - ICON // 2, ty - ICON, c, s['fg-color'], s['bg-color']) + display.icon(tx - ICON // 2, ty - ICON, c, s["fg-color"], s["bg-color"]) def touch(self, event, pos): pos = rotate(pos) diff --git a/src/trezor/ui/confirm.py b/src/trezor/ui/confirm.py index 5e1227e6e..995a2ec01 100644 --- a/src/trezor/ui/confirm.py +++ b/src/trezor/ui/confirm.py @@ -15,21 +15,20 @@ DEFAULT_CANCEL = res.load(ui.ICON_CANCEL) class ConfirmDialog(Widget): - def __init__(self, - content, - confirm=DEFAULT_CONFIRM, - cancel=DEFAULT_CANCEL, - confirm_style=ui.BTN_CONFIRM, - cancel_style=ui.BTN_CANCEL): + def __init__( + self, + content, + confirm=DEFAULT_CONFIRM, + cancel=DEFAULT_CANCEL, + confirm_style=ui.BTN_CONFIRM, + cancel_style=ui.BTN_CANCEL, + ): self.content = content if cancel is not None: - self.confirm = Button( - ui.grid(9, n_x=2), confirm, style=confirm_style) - self.cancel = Button( - ui.grid(8, n_x=2), cancel, style=cancel_style) + self.confirm = Button(ui.grid(9, n_x=2), confirm, style=confirm_style) + self.cancel = Button(ui.grid(8, n_x=2), cancel, style=cancel_style) else: - self.confirm = Button( - ui.grid(4, n_x=1), confirm, style=confirm_style) + self.confirm = Button(ui.grid(4, n_x=1), confirm, style=confirm_style) self.cancel = None def render(self): @@ -56,12 +55,13 @@ _STOPPED = const(-2) class HoldToConfirmDialog(Widget): - - def __init__(self, - content, - hold='Hold to confirm', - button_style=ui.BTN_CONFIRM, - loader_style=ui.LDR_DEFAULT): + def __init__( + self, + content, + hold="Hold to confirm", + button_style=ui.BTN_CONFIRM, + loader_style=ui.LDR_DEFAULT, + ): self.content = content self.button = Button(ui.grid(4, n_x=1), hold, style=button_style) self.loader = Loader(style=loader_style) diff --git a/src/trezor/ui/container.py b/src/trezor/ui/container.py index 6f53ac4e8..7ebf462ba 100644 --- a/src/trezor/ui/container.py +++ b/src/trezor/ui/container.py @@ -2,7 +2,6 @@ from trezor.ui import Widget class Container(Widget): - def __init__(self, *children): self.children = children diff --git a/src/trezor/ui/entry_select.py b/src/trezor/ui/entry_select.py index 42531953d..33dbdca3b 100644 --- a/src/trezor/ui/entry_select.py +++ b/src/trezor/ui/entry_select.py @@ -9,11 +9,10 @@ HOST = const(1) class EntrySelector(Widget): - def __init__(self, content): self.content = content - self.device = Button(ui.grid(8, n_y=4, n_x=4, cells_x=4), 'Device') - self.host = Button(ui.grid(12, n_y=4, n_x=4, cells_x=4), 'Host') + self.device = Button(ui.grid(8, n_y=4, n_x=4, cells_x=4), "Device") + self.host = Button(ui.grid(12, n_y=4, n_x=4, cells_x=4), "Host") def render(self): self.device.render() diff --git a/src/trezor/ui/loader.py b/src/trezor/ui/loader.py index d16531ddc..6e19c8c99 100644 --- a/src/trezor/ui/loader.py +++ b/src/trezor/ui/loader.py @@ -8,11 +8,10 @@ _SHRINK_BY = const(2) class Loader(ui.Widget): - def __init__(self, style=ui.LDR_DEFAULT): self.target_ms = _TARGET_MS - self.normal_style = style['normal'] or ui.LDR_DEFAULT['normal'] - self.active_style = style['active'] or ui.LDR_DEFAULT['active'] + self.normal_style = style["normal"] or ui.LDR_DEFAULT["normal"] + self.active_style = style["active"] or ui.LDR_DEFAULT["active"] self.start_ms = None self.stop_ms = None @@ -47,15 +46,19 @@ class Loader(ui.Widget): s = self.active_style else: s = self.normal_style - if s['icon'] is None: - ui.display.loader( - r, -24, s['fg-color'], s['bg-color']) - elif s['icon-fg-color'] is None: - ui.display.loader( - r, -24, s['fg-color'], s['bg-color'], res.load(s['icon'])) + if s["icon"] is None: + ui.display.loader(r, -24, s["fg-color"], s["bg-color"]) + elif s["icon-fg-color"] is None: + ui.display.loader(r, -24, s["fg-color"], s["bg-color"], res.load(s["icon"])) else: ui.display.loader( - r, -24, s['fg-color'], s['bg-color'], res.load(s['icon']), s['icon-fg-color']) + r, + -24, + s["fg-color"], + s["bg-color"], + res.load(s["icon"]), + s["icon-fg-color"], + ) def __iter__(self): sleep = loop.sleep(1000000 // 30) # 30 fps diff --git a/src/trezor/ui/mnemonic.py b/src/trezor/ui/mnemonic.py index 1964c9a4a..75d830e70 100644 --- a/src/trezor/ui/mnemonic.py +++ b/src/trezor/ui/mnemonic.py @@ -6,7 +6,7 @@ from trezor.ui.button import BTN_CLICKED, ICON, Button if __debug__: from apps.debug import input_signal -MNEMONIC_KEYS = ('abc', 'def', 'ghi', 'jkl', 'mno', 'pqr', 'stu', 'vwx', 'yz') +MNEMONIC_KEYS = ("abc", "def", "ghi", "jkl", "mno", "pqr", "stu", "vwx", "yz") def key_buttons(keys): @@ -24,7 +24,7 @@ def compute_mask(text: str) -> int: class Input(Button): - def __init__(self, area: tuple, content: str='', word: str=''): + def __init__(self, area: tuple, content: str = "", word: str = ""): super().__init__(area, content) self.word = word self.icon = None @@ -37,26 +37,26 @@ class Input(Button): self.taint() if content == word: # confirm button self.enable() - self.normal_style = ui.BTN_KEY_CONFIRM['normal'] - self.active_style = ui.BTN_KEY_CONFIRM['active'] + self.normal_style = ui.BTN_KEY_CONFIRM["normal"] + self.active_style = ui.BTN_KEY_CONFIRM["active"] self.icon = ui.ICON_CONFIRM elif word: # auto-complete button self.enable() - self.normal_style = ui.BTN_KEY['normal'] - self.active_style = ui.BTN_KEY['active'] + self.normal_style = ui.BTN_KEY["normal"] + self.active_style = ui.BTN_KEY["active"] self.icon = ui.ICON_CLICK else: # disabled button self.disable() self.icon = None def render_content(self, s, ax, ay, aw, ah): - text_style = s['text-style'] - fg_color = s['fg-color'] - bg_color = s['bg-color'] + text_style = s["text-style"] + fg_color = s["fg-color"] + bg_color = s["bg-color"] p = self.pending # should we draw the pending marker? t = self.content # input content - w = self.word[len(t):] # suggested word + w = self.word[len(t) :] # suggested word i = self.icon # rendered icon tx = ax + 24 # x-offset of the content @@ -79,12 +79,12 @@ class Input(Button): class MnemonicKeyboard(ui.Widget): - def __init__(self, prompt: str=''): + def __init__(self, prompt: str = ""): self.prompt = prompt - self.input = Input(ui.grid(1, n_x=4, n_y=4, cells_x=3), '', '') - self.back = Button(ui.grid(0, n_x=4, n_y=4), - res.load(ui.ICON_BACK), - style=ui.BTN_CLEAR) + self.input = Input(ui.grid(1, n_x=4, n_y=4, cells_x=3), "", "") + self.back = Button( + ui.grid(0, n_x=4, n_y=4), res.load(ui.ICON_BACK), style=ui.BTN_CLEAR + ) self.keys = key_buttons(MNEMONIC_KEYS) self.pbutton = None # pending key button self.pindex = 0 # index of current pending char in pbutton @@ -114,7 +114,7 @@ class MnemonicKeyboard(ui.Widget): if self.input.touch(event, pos) == BTN_CLICKED: # input press, either auto-complete or confirm if word and content == word: - self.edit('') + self.edit("") return content else: self.edit(word) @@ -133,7 +133,7 @@ class MnemonicKeyboard(ui.Widget): return def edit(self, content, button=None, index=0): - word = bip39.find_word(content) or '' + word = bip39.find_word(content) or "" mask = bip39.complete_word(content) self.pbutton = button diff --git a/src/trezor/ui/passphrase.py b/src/trezor/ui/passphrase.py index a3ea4f32c..340b3b406 100644 --- a/src/trezor/ui/passphrase.py +++ b/src/trezor/ui/passphrase.py @@ -8,10 +8,11 @@ from trezor.ui.swipe import SWIPE_HORIZONTAL, SWIPE_LEFT, Swipe SPACE = res.load(ui.ICON_SPACE) KEYBOARD_KEYS = ( - ('1', '2', '3', '4', '5', '6', '7', '8', '9', '0'), - (SPACE, 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz', '*#'), - (SPACE, 'ABC', 'DEF', 'GHI', 'JKL', 'MNO', 'PQRS', 'TUV', 'WXYZ', '*#'), - ('_<>', '.:@', '/|\\', '!()', '+%&', '-[]', '?{}', ',\'`', ';"~', '$^=')) + ("1", "2", "3", "4", "5", "6", "7", "8", "9", "0"), + (SPACE, "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz", "*#"), + (SPACE, "ABC", "DEF", "GHI", "JKL", "MNO", "PQRS", "TUV", "WXYZ", "*#"), + ("_<>", ".:@", "/|\\", "!()", "+%&", "-[]", "?{}", ",'`", ';"~', "$^="), +) def digit_area(i): @@ -39,13 +40,13 @@ def render_scrollbar(page): for i in range(0, page_count): if i != page: ui.display.bar_radius( - x + i * padding, y, size, size, ui.DARK_GREY, ui.BG, size // 2) - ui.display.bar_radius( - x + page * padding, y, size, size, ui.FG, ui.BG, size // 2) + x + i * padding, y, size, size, ui.DARK_GREY, ui.BG, size // 2 + ) + ui.display.bar_radius(x + page * padding, y, size, size, ui.FG, ui.BG, size // 2) class Input(Button): - def __init__(self, area: tuple, content: str=''): + def __init__(self, area: tuple, content: str = ""): super().__init__(area, content) self.pending = False self.disable() @@ -56,9 +57,9 @@ class Input(Button): self.taint() def render_content(self, s, ax, ay, aw, ah): - text_style = s['text-style'] - fg_color = s['fg-color'] - bg_color = s['bg-color'] + text_style = s["text-style"] + fg_color = s["fg-color"] + bg_color = s["bg-color"] p = self.pending # should we draw the pending marker? t = self.content # input content @@ -69,7 +70,7 @@ class Input(Button): # input content if len(t) > maxlen: - t = '<' + t[-maxlen:] # too long, align to the right + t = "<" + t[-maxlen:] # too long, align to the right width = display.text_width(t, text_style) display.text(tx, ty, t, text_style, fg_color, bg_color) @@ -102,7 +103,7 @@ class PassphraseKeyboard(ui.Widget): def __init__(self, prompt, page=1): self.prompt = Prompt(prompt) self.page = page - self.input = Input(ui.grid(0, n_x=1, n_y=6), '') + self.input = Input(ui.grid(0, n_x=1, n_y=6), "") self.back = Button(ui.grid(12), res.load(ui.ICON_BACK), style=ui.BTN_CLEAR) self.done = Button(ui.grid(14), res.load(ui.ICON_CONFIRM), style=ui.BTN_CONFIRM) self.keys = key_buttons(KEYBOARD_KEYS[self.page]) @@ -147,7 +148,7 @@ class PassphraseKeyboard(ui.Widget): content += btn.content[0] else: index = 0 - content += ' ' + content += " " self.edit(content, btn, index) return diff --git a/src/trezor/ui/pin.py b/src/trezor/ui/pin.py index 8b1cd36aa..94baf9cb2 100644 --- a/src/trezor/ui/pin.py +++ b/src/trezor/ui/pin.py @@ -19,8 +19,7 @@ def generate_digits(): class PinMatrix(ui.Widget): - - def __init__(self, label, pin='', maxlength=9): + def __init__(self, label, pin="", maxlength=9): self.label = label self.pin = pin self.maxlength = maxlength @@ -30,8 +29,9 @@ class PinMatrix(ui.Widget): # digits is defined as bottom-left to top-right (on numpad) reordered_digits = self.digits[6:] + self.digits[3:6] + self.digits[:3] - self.pin_buttons = [Button(digit_area(i), str(d)) - for i, d in enumerate(reordered_digits)] + self.pin_buttons = [ + Button(digit_area(i), str(d)) for i, d in enumerate(reordered_digits) + ] self.onchange = None def render(self): diff --git a/src/trezor/ui/qr.py b/src/trezor/ui/qr.py index b23960e52..d573dbdd1 100644 --- a/src/trezor/ui/qr.py +++ b/src/trezor/ui/qr.py @@ -2,7 +2,6 @@ from trezor import ui class Qr(ui.Widget): - def __init__(self, data, pos, scale): self.data = data self.pos = pos diff --git a/src/trezor/ui/scroll.py b/src/trezor/ui/scroll.py index 6594affef..3ca494db5 100644 --- a/src/trezor/ui/scroll.py +++ b/src/trezor/ui/scroll.py @@ -42,7 +42,7 @@ async def animate_swipe(): time_delay = const(40000) draw_delay = const(200000) - ui.display.text_center(130, 220, 'Swipe', ui.BOLD, ui.GREY, ui.BG) + ui.display.text_center(130, 220, "Swipe", ui.BOLD, ui.GREY, ui.BG) sleep = loop.sleep(time_delay) icon = res.load(ui.ICON_SWIPE) @@ -65,14 +65,11 @@ def render_scrollbar(page, page_count): for i in range(0, page_count): if i != page: - ui.display.bar_radius(x, y + i * padding, size, - size, ui.GREY, ui.BG, 4) - ui.display.bar_radius(x, y + page * padding, size, - size, ui.FG, ui.BG, 4) + ui.display.bar_radius(x, y + i * padding, size, size, ui.GREY, ui.BG, 4) + ui.display.bar_radius(x, y + page * padding, size, size, ui.FG, ui.BG, 4) class Scrollpage(ui.Widget): - def __init__(self, content, page, page_count): self.content = content self.page = page diff --git a/src/trezor/ui/style.py b/src/trezor/ui/style.py index f3722fc3a..ca92e97ea 100644 --- a/src/trezor/ui/style.py +++ b/src/trezor/ui/style.py @@ -7,37 +7,37 @@ RADIUS = const(2) # backlight brightness BACKLIGHT_NORMAL = const(150) -BACKLIGHT_DIM = const(5) -BACKLIGHT_NONE = const(2) -BACKLIGHT_MAX = const(255) +BACKLIGHT_DIM = const(5) +BACKLIGHT_NONE = const(2) +BACKLIGHT_MAX = const(255) # color palette -RED = rgb(0xFF, 0x00, 0x00) -PINK = rgb(0xE9, 0x1E, 0x63) -PURPLE = rgb(0x9C, 0x27, 0xB0) +RED = rgb(0xFF, 0x00, 0x00) +PINK = rgb(0xE9, 0x1E, 0x63) +PURPLE = rgb(0x9C, 0x27, 0xB0) DEEP_PURPLE = rgb(0x67, 0x3A, 0xB7) -INDIGO = rgb(0x3F, 0x51, 0xB5) -BLUE = rgb(0x21, 0x96, 0xF3) -LIGHT_BLUE = rgb(0x03, 0xA9, 0xF4) -CYAN = rgb(0x00, 0xBC, 0xD4) -TEAL = rgb(0x00, 0x96, 0x88) -GREEN = rgb(0x00, 0xAE, 0x0B) +INDIGO = rgb(0x3F, 0x51, 0xB5) +BLUE = rgb(0x21, 0x96, 0xF3) +LIGHT_BLUE = rgb(0x03, 0xA9, 0xF4) +CYAN = rgb(0x00, 0xBC, 0xD4) +TEAL = rgb(0x00, 0x96, 0x88) +GREEN = rgb(0x00, 0xAE, 0x0B) LIGHT_GREEN = rgb(0x87, 0xCE, 0x26) -LIME = rgb(0xCD, 0xDC, 0x39) -YELLOW = rgb(0xFF, 0xEB, 0x3B) -AMBER = rgb(0xFF, 0xC1, 0x07) -ORANGE = rgb(0xFF, 0x98, 0x00) +LIME = rgb(0xCD, 0xDC, 0x39) +YELLOW = rgb(0xFF, 0xEB, 0x3B) +AMBER = rgb(0xFF, 0xC1, 0x07) +ORANGE = rgb(0xFF, 0x98, 0x00) DEEP_ORANGE = rgb(0xFF, 0x57, 0x22) -BROWN = rgb(0x79, 0x55, 0x48) -LIGHT_GREY = rgb(0xDA, 0xDD, 0xD8) -GREY = rgb(0x9E, 0x9E, 0x9E) -DARK_GREY = rgb(0x3E, 0x3E, 0x3E) -BLUE_GRAY = rgb(0x60, 0x7D, 0x8B) -BLACK = rgb(0x00, 0x00, 0x00) -WHITE = rgb(0xFA, 0xFA, 0xFA) -BLACKISH = rgb(0x30, 0x30, 0x30) - -TITLE_GREY = rgb(0x9B, 0x9B, 0x9B) +BROWN = rgb(0x79, 0x55, 0x48) +LIGHT_GREY = rgb(0xDA, 0xDD, 0xD8) +GREY = rgb(0x9E, 0x9E, 0x9E) +DARK_GREY = rgb(0x3E, 0x3E, 0x3E) +BLUE_GRAY = rgb(0x60, 0x7D, 0x8B) +BLACK = rgb(0x00, 0x00, 0x00) +WHITE = rgb(0xFA, 0xFA, 0xFA) +BLACKISH = rgb(0x30, 0x30, 0x30) + +TITLE_GREY = rgb(0x9B, 0x9B, 0x9B) ORANGE_ICON = rgb(0xF5, 0xA6, 0x23) # common color styles @@ -45,198 +45,188 @@ BG = BLACK FG = WHITE # icons -ICON_RESET = 'trezor/res/header_icons/reset.toig' -ICON_WIPE = 'trezor/res/header_icons/wipe.toig' -ICON_RECOVERY = 'trezor/res/header_icons/recovery.toig' -ICON_NOCOPY = 'trezor/res/header_icons/nocopy.toig' -ICON_WRONG = 'trezor/res/header_icons/wrong.toig' -ICON_CONFIG = 'trezor/res/header_icons/cog.toig' -ICON_RECEIVE = 'trezor/res/header_icons/receive.toig' -ICON_SEND = 'trezor/res/header_icons/send.toig' - -ICON_DEFAULT = ICON_CONFIG - -ICON_CANCEL = 'trezor/res/cancel.toig' -ICON_CONFIRM = 'trezor/res/confirm.toig' -ICON_LOCK = 'trezor/res/lock.toig' -ICON_CLICK = 'trezor/res/click.toig' -ICON_BACK = 'trezor/res/left.toig' -ICON_SWIPE = 'trezor/res/swipe.toig' -ICON_CHECK = 'trezor/res/check.toig' -ICON_SPACE = 'trezor/res/space.toig' +ICON_RESET = "trezor/res/header_icons/reset.toig" +ICON_WIPE = "trezor/res/header_icons/wipe.toig" +ICON_RECOVERY = "trezor/res/header_icons/recovery.toig" +ICON_NOCOPY = "trezor/res/header_icons/nocopy.toig" +ICON_WRONG = "trezor/res/header_icons/wrong.toig" +ICON_CONFIG = "trezor/res/header_icons/cog.toig" +ICON_RECEIVE = "trezor/res/header_icons/receive.toig" +ICON_SEND = "trezor/res/header_icons/send.toig" + +ICON_DEFAULT = ICON_CONFIG + +ICON_CANCEL = "trezor/res/cancel.toig" +ICON_CONFIRM = "trezor/res/confirm.toig" +ICON_LOCK = "trezor/res/lock.toig" +ICON_CLICK = "trezor/res/click.toig" +ICON_BACK = "trezor/res/left.toig" +ICON_SWIPE = "trezor/res/swipe.toig" +ICON_CHECK = "trezor/res/check.toig" +ICON_SPACE = "trezor/res/space.toig" # buttons BTN_DEFAULT = { - 'normal': { - 'bg-color': BG, - 'fg-color': FG, - 'text-style': NORMAL, - 'border-color': BG, - 'radius': RADIUS, - }, - 'active': { - 'bg-color': FG, - 'fg-color': BG, - 'text-style': BOLD, - 'border-color': FG, - 'radius': RADIUS, - }, - 'disabled': { - 'bg-color': BG, - 'fg-color': GREY, - 'text-style': NORMAL, - 'border-color': BG, - 'radius': RADIUS, - } + "normal": { + "bg-color": BG, + "fg-color": FG, + "text-style": NORMAL, + "border-color": BG, + "radius": RADIUS, + }, + "active": { + "bg-color": FG, + "fg-color": BG, + "text-style": BOLD, + "border-color": FG, + "radius": RADIUS, + }, + "disabled": { + "bg-color": BG, + "fg-color": GREY, + "text-style": NORMAL, + "border-color": BG, + "radius": RADIUS, + }, } BTN_CANCEL = { - 'normal': { - 'bg-color': RED, - 'fg-color': FG, - 'text-style': BOLD, - 'border-color': BG, - 'radius': RADIUS, - }, - 'active': { - 'bg-color': FG, - 'fg-color': RED, - 'text-style': BOLD, - 'border-color': FG, - 'radius': RADIUS, - }, - 'disabled': { - 'bg-color': BG, - 'fg-color': GREY, - 'text-style': NORMAL, - 'border-color': BG, - 'radius': RADIUS, - } + "normal": { + "bg-color": RED, + "fg-color": FG, + "text-style": BOLD, + "border-color": BG, + "radius": RADIUS, + }, + "active": { + "bg-color": FG, + "fg-color": RED, + "text-style": BOLD, + "border-color": FG, + "radius": RADIUS, + }, + "disabled": { + "bg-color": BG, + "fg-color": GREY, + "text-style": NORMAL, + "border-color": BG, + "radius": RADIUS, + }, } BTN_CONFIRM = { - 'normal': { - 'bg-color': GREEN, - 'fg-color': FG, - 'text-style': BOLD, - 'border-color': BG, - 'radius': RADIUS, - }, - 'active': { - 'bg-color': FG, - 'fg-color': GREEN, - 'text-style': BOLD, - 'border-color': FG, - 'radius': RADIUS, - }, - 'disabled': { - 'bg-color': BG, - 'fg-color': GREY, - 'text-style': NORMAL, - 'border-color': BG, - 'radius': RADIUS, - } + "normal": { + "bg-color": GREEN, + "fg-color": FG, + "text-style": BOLD, + "border-color": BG, + "radius": RADIUS, + }, + "active": { + "bg-color": FG, + "fg-color": GREEN, + "text-style": BOLD, + "border-color": FG, + "radius": RADIUS, + }, + "disabled": { + "bg-color": BG, + "fg-color": GREY, + "text-style": NORMAL, + "border-color": BG, + "radius": RADIUS, + }, } BTN_CLEAR = { - 'normal': { - 'bg-color': ORANGE, - 'fg-color': FG, - 'text-style': NORMAL, - 'border-color': BG, - 'radius': RADIUS, - }, - 'active': { - 'bg-color': BG, - 'fg-color': GREY, - 'text-style': NORMAL, - 'border-color': BG, - 'radius': RADIUS, - }, - 'disabled': { - 'bg-color': BG, - 'fg-color': GREY, - 'text-style': MONO, - 'border-color': BG, - 'radius': RADIUS, - } + "normal": { + "bg-color": ORANGE, + "fg-color": FG, + "text-style": NORMAL, + "border-color": BG, + "radius": RADIUS, + }, + "active": { + "bg-color": BG, + "fg-color": GREY, + "text-style": NORMAL, + "border-color": BG, + "radius": RADIUS, + }, + "disabled": { + "bg-color": BG, + "fg-color": GREY, + "text-style": MONO, + "border-color": BG, + "radius": RADIUS, + }, } BTN_KEY = { - 'normal': { - 'bg-color': BLACKISH, - 'fg-color': FG, - 'text-style': MONO, - 'border-color': BG, - 'radius': RADIUS, - }, - 'active': { - 'bg-color': FG, - 'fg-color': BLACKISH, - 'text-style': MONO, - 'border-color': FG, - 'radius': RADIUS, - }, - 'disabled': { - 'bg-color': BG, - 'fg-color': GREY, - 'text-style': MONO, - 'border-color': BG, - 'radius': RADIUS, - } + "normal": { + "bg-color": BLACKISH, + "fg-color": FG, + "text-style": MONO, + "border-color": BG, + "radius": RADIUS, + }, + "active": { + "bg-color": FG, + "fg-color": BLACKISH, + "text-style": MONO, + "border-color": FG, + "radius": RADIUS, + }, + "disabled": { + "bg-color": BG, + "fg-color": GREY, + "text-style": MONO, + "border-color": BG, + "radius": RADIUS, + }, } BTN_KEY_CONFIRM = { - 'normal': { - 'bg-color': GREEN, - 'fg-color': FG, - 'text-style': MONO, - 'border-color': BG, - 'radius': RADIUS, - }, - 'active': { - 'bg-color': FG, - 'fg-color': GREEN, - 'text-style': MONO, - 'border-color': FG, - 'radius': RADIUS, - }, - 'disabled': { - 'bg-color': BG, - 'fg-color': GREY, - 'text-style': MONO, - 'border-color': BG, - 'radius': RADIUS, - } + "normal": { + "bg-color": GREEN, + "fg-color": FG, + "text-style": MONO, + "border-color": BG, + "radius": RADIUS, + }, + "active": { + "bg-color": FG, + "fg-color": GREEN, + "text-style": MONO, + "border-color": FG, + "radius": RADIUS, + }, + "disabled": { + "bg-color": BG, + "fg-color": GREY, + "text-style": MONO, + "border-color": BG, + "radius": RADIUS, + }, } # loader LDR_DEFAULT = { - 'normal': { - 'bg-color': BG, - 'fg-color': GREEN, - 'icon': None, - 'icon-fg-color': None, - }, - 'active': { - 'bg-color': BG, - 'fg-color': GREEN, - 'icon': ICON_CHECK, - 'icon-fg-color': WHITE, - } + "normal": {"bg-color": BG, "fg-color": GREEN, "icon": None, "icon-fg-color": None}, + "active": { + "bg-color": BG, + "fg-color": GREEN, + "icon": ICON_CHECK, + "icon-fg-color": WHITE, + }, } LDR_DANGER = { - 'normal': { - 'bg-color': BG, - 'fg-color': RED, - 'icon': None, - 'icon-fg-color': None, - }, - 'active': { - 'bg-color': BG, - 'fg-color': RED, - 'icon': ICON_CHECK, - 'icon-fg-color': WHITE, - } + "normal": {"bg-color": BG, "fg-color": RED, "icon": None, "icon-fg-color": None}, + "active": { + "bg-color": BG, + "fg-color": RED, + "icon": ICON_CHECK, + "icon-fg-color": WHITE, + }, } diff --git a/src/trezor/ui/swipe.py b/src/trezor/ui/swipe.py index 941c2cb3a..7f371753c 100644 --- a/src/trezor/ui/swipe.py +++ b/src/trezor/ui/swipe.py @@ -26,7 +26,6 @@ def degrees(swipe: int) -> int: class Swipe(ui.Widget): - def __init__(self, area=None, absolute=False, directions=SWIPE_ALL, treshold=30): self.area = area or (0, 0, ui.WIDTH, ui.HEIGHT) self.absolute = absolute @@ -49,18 +48,28 @@ class Swipe(ui.Widget): pdya = abs(pdy) if pdxa > pdya and self.directions & SWIPE_HORIZONTAL: # Horizontal direction - if (pdx > 0 and self.directions & SWIPE_RIGHT) or (pdx < 0 and self.directions & SWIPE_LEFT): - ui.display.backlight(ui.lerpi( - self.light_origin, - self.light_target, - pdxa / _SWIPE_DISTANCE if pdxa < _SWIPE_DISTANCE else 1)) + if (pdx > 0 and self.directions & SWIPE_RIGHT) or ( + pdx < 0 and self.directions & SWIPE_LEFT + ): + ui.display.backlight( + ui.lerpi( + self.light_origin, + self.light_target, + pdxa / _SWIPE_DISTANCE if pdxa < _SWIPE_DISTANCE else 1, + ) + ) elif pdxa < pdya and self.directions & SWIPE_VERTICAL: # Vertical direction - if (pdy > 0 and self.directions & SWIPE_DOWN) or (pdy < 0 and self.directions & SWIPE_UP): - ui.display.backlight(ui.lerpi( - self.light_origin, - self.light_target, - pdya / _SWIPE_DISTANCE if pdya < _SWIPE_DISTANCE else 1)) + if (pdy > 0 and self.directions & SWIPE_DOWN) or ( + pdy < 0 and self.directions & SWIPE_UP + ): + ui.display.backlight( + ui.lerpi( + self.light_origin, + self.light_target, + pdya / _SWIPE_DISTANCE if pdya < _SWIPE_DISTANCE else 1, + ) + ) elif event == io.TOUCH_START and contains(self.area, pos): self.start_pos = pos diff --git a/src/trezor/ui/text.py b/src/trezor/ui/text.py index 60a0b9a1b..c02b82f0b 100644 --- a/src/trezor/ui/text.py +++ b/src/trezor/ui/text.py @@ -22,9 +22,9 @@ def render_text(words: list, new_lines: bool, max_lines: int) -> None: OFFSET_Y_MAX = TEXT_HEADER_HEIGHT + TEXT_LINE_HEIGHT * max_lines # sizes of common glyphs - SPACE = ui.display.text_width(' ', font) - DASH = ui.display.text_width('-', ui.BOLD) - ELLIPSIS = ui.display.text_width('...', ui.BOLD) + SPACE = ui.display.text_width(" ", font) + DASH = ui.display.text_width("-", ui.BOLD) + ELLIPSIS = ui.display.text_width("...", ui.BOLD) for word_index, word in enumerate(words): has_next_word = word_index < len(words) - 1 @@ -33,7 +33,7 @@ def render_text(words: list, new_lines: bool, max_lines: int) -> None: if word == BR: # line break if offset_y >= OFFSET_Y_MAX: - ui.display.text(offset_x, offset_y, '...', ui.BOLD, ui.GREY, bg) + ui.display.text(offset_x, offset_y, "...", ui.BOLD, ui.GREY, bg) return offset_x = TEXT_MARGIN_LEFT offset_y += TEXT_LINE_HEIGHT @@ -47,20 +47,26 @@ 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) - if offset_y < OFFSET_Y_MAX and word_fits_in_one_line and not beginning_of_line: + if ( + offset_y < OFFSET_Y_MAX + and word_fits_in_one_line + and not beginning_of_line + ): # line break offset_x = TEXT_MARGIN_LEFT offset_y += TEXT_LINE_HEIGHT break # word split if offset_y < OFFSET_Y_MAX: - split = '-' + split = "-" splitw = DASH else: - split = '...' + split = "..." splitw = ELLIPSIS # find span that fits for index in range(len(word) - 1, 0, -1): @@ -89,7 +95,7 @@ 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: - ui.display.text(offset_x, offset_y, '...', ui.BOLD, ui.GREY, bg) + ui.display.text(offset_x, offset_y, "...", ui.BOLD, ui.GREY, bg) return offset_x = TEXT_MARGIN_LEFT offset_y += TEXT_LINE_HEIGHT @@ -100,12 +106,14 @@ def render_text(words: list, new_lines: bool, max_lines: int) -> None: class Text(ui.LazyWidget): - def __init__(self, - header_text: str, - header_icon: str = ui.ICON_DEFAULT, - icon_color: int = ui.ORANGE_ICON, - max_lines: int = TEXT_MAX_LINES, - new_lines: bool = True): + def __init__( + self, + header_text: str, + header_icon: str = ui.ICON_DEFAULT, + icon_color: int = ui.ORANGE_ICON, + max_lines: int = TEXT_MAX_LINES, + new_lines: bool = True, + ): self.header_text = header_text self.header_icon = header_icon self.icon_color = icon_color @@ -127,5 +135,7 @@ class Text(ui.LazyWidget): self.content.append(ui.NORMAL) def render(self): - ui.header(self.header_text, self.header_icon, ui.TITLE_GREY, ui.BG, self.icon_color) + ui.header( + self.header_text, self.header_icon, ui.TITLE_GREY, ui.BG, self.icon_color + ) render_text(self.content, self.new_lines, self.max_lines) diff --git a/src/trezor/ui/word_select.py b/src/trezor/ui/word_select.py index 49963f9a4..995f4ba71 100644 --- a/src/trezor/ui/word_select.py +++ b/src/trezor/ui/word_select.py @@ -14,15 +14,17 @@ _W24 = const(24) class WordSelector(Widget): - def __init__(self, content): self.content = content - self.w12 = Button(ui.grid(6, n_y=4, n_x=3, cells_y=2), str(_W12), - style=ui.BTN_KEY) - self.w18 = Button(ui.grid(7, n_y=4, n_x=3, cells_y=2), str(_W18), - style=ui.BTN_KEY) - self.w24 = Button(ui.grid(8, n_y=4, n_x=3, cells_y=2), str(_W24), - style=ui.BTN_KEY) + self.w12 = Button( + ui.grid(6, n_y=4, n_x=3, cells_y=2), str(_W12), style=ui.BTN_KEY + ) + self.w18 = Button( + ui.grid(7, n_y=4, n_x=3, cells_y=2), str(_W18), style=ui.BTN_KEY + ) + self.w24 = Button( + ui.grid(8, n_y=4, n_x=3, cells_y=2), str(_W24), style=ui.BTN_KEY + ) def render(self): self.w12.render() diff --git a/src/trezor/utils.py b/src/trezor/utils.py index abef8828c..671d57f4f 100644 --- a/src/trezor/utils.py +++ b/src/trezor/utils.py @@ -13,11 +13,11 @@ def unimport_end(mods): # remove reference from sys.modules del sys.modules[mod] # remove reference from the parent module - i = mod.rfind('.') + i = mod.rfind(".") if i < 0: continue path = mod[:i] - name = mod[i + 1:] + name = mod[i + 1 :] if path in sys.modules: delattr(sys.modules[path], name) # collect removed modules @@ -34,44 +34,45 @@ def ensure(cond, msg=None): def chunks(items, size): for i in range(0, len(items), size): - yield items[i:i + size] + yield items[i : i + size] def split_words(sentence, width, metric=len): line = [] - for w in sentence.split(' '): + for w in sentence.split(" "): # empty word -> skip if not w: continue # new word will not fit -> break the line - if metric(' '.join(line + [w])) >= width: - yield ' '.join(line) + if metric(" ".join(line + [w])) >= width: + yield " ".join(line) line = [] # word is too wide -> split the word while metric(w) >= width: for i in range(1, len(w) + 1): if metric(w[:-i]) < width: - yield w[:-i] + '-' + yield w[:-i] + "-" w = w[-i:] break line.append(w) - yield ' '.join(line) + yield " ".join(line) def format_amount(amount, decimals): d = pow(10, decimals) - amount = ('%d.%0*d' % (amount // d, decimals, amount % d)).rstrip('0') - if amount.endswith('.'): + amount = ("%d.%0*d" % (amount // d, decimals, amount % d)).rstrip("0") + if amount.endswith("."): amount = amount[:-1] return amount def format_ordinal(number): - return str(number) + {1: 'st', 2: 'nd', 3: 'rd'}.get(4 if 10 <= number % 100 < 20 else number % 10, 'th') + return str(number) + {1: "st", 2: "nd", 3: "rd"}.get( + 4 if 10 <= number % 100 < 20 else number % 10, "th" + ) class HashWriter: - def __init__(self, hashfunc, *hashargs, **hashkwargs): self.ctx = hashfunc(*hashargs, **hashkwargs) self.buf = bytearray(1) # used in append() diff --git a/src/trezor/wire/__init__.py b/src/trezor/wire/__init__.py index 4b7de8c30..b8235da45 100644 --- a/src/trezor/wire/__init__.py +++ b/src/trezor/wire/__init__.py @@ -7,7 +7,7 @@ workflow_handlers = {} def register(mtype, handler, *args): - '''Register `handler` to get scheduled after `mtype` message is received.''' + """Register `handler` to get scheduled after `mtype` message is received.""" if isinstance(mtype, type) and issubclass(mtype, protobuf.MessageType): mtype = mtype.MESSAGE_WIRE_TYPE if mtype in workflow_handlers: @@ -16,7 +16,7 @@ def register(mtype, handler, *args): def setup(iface): - '''Initialize the wire stack on passed USB interface.''' + """Initialize the wire stack on passed USB interface.""" loop.schedule(session_handler(iface, codec_v1.SESSION_ID)) @@ -26,24 +26,25 @@ class Context: self.sid = sid async def call(self, msg, *types): - ''' + """ Reply with `msg` and wait for one of `types`. See `self.write()` and `self.read()`. - ''' + """ await self.write(msg) return await self.read(types) async def read(self, types): - ''' + """ Wait for incoming message on this wire context and return it. Raises `UnexpectedMessageError` if the message type does not match one of `types`; and caller should always make sure to re-raise it. - ''' + """ reader = self.getreader() if __debug__: - log.debug(__name__, '%s:%x read: %s', - self.iface.iface_num(), self.sid, types) + log.debug( + __name__, "%s:%x read: %s", self.iface.iface_num(), self.sid, types + ) await reader.aopen() # wait for the message header @@ -57,14 +58,15 @@ class Context: return await protobuf.load_message(reader, pbtype) async def write(self, msg): - ''' + """ Write a protobuf message to this wire context. - ''' + """ writer = self.getwriter() if __debug__: - log.debug(__name__, '%s:%x write: %s', - self.iface.iface_num(), self.sid, msg) + log.debug( + __name__, "%s:%x write: %s", self.iface.iface_num(), self.sid, msg + ) # get the message size counter = protobuf.CountingWriter() @@ -76,11 +78,11 @@ class Context: await writer.aclose() def wait(self, *tasks): - ''' + """ Wait until one of the passed tasks finishes, and return the result, while servicing the wire context. If a message comes until one of the tasks ends, `UnexpectedMessageError` is raised. - ''' + """ return loop.spawn(self.read(()), *tasks) def getreader(self): @@ -125,7 +127,7 @@ async def session_handler(iface, sid): continue except Error as exc: # we log wire.Error as warning, not as exception - log.warning(__name__, 'failure: %s', exc.message) + log.warning(__name__, "failure: %s", exc.message) except Exception as exc: # sessions are never closed by raised exceptions log.exception(__name__, exc) @@ -149,7 +151,9 @@ async def protobuf_workflow(ctx, reader, handler, *args): raise except Exception as exc: # respond with a generic code and message - await ctx.write(Failure(code=FailureType.FirmwareError, message='Firmware error')) + await ctx.write( + Failure(code=FailureType.FirmwareError, message="Firmware error") + ) raise if res: # respond with a specific response @@ -165,4 +169,6 @@ async def unexpected_msg(ctx, reader): await reader.areadinto(buf) # respond with an unknown message error - await ctx.write(Failure(code=FailureType.UnexpectedMessage, message='Unexpected message')) + await ctx.write( + Failure(code=FailureType.UnexpectedMessage, message="Unexpected message") + ) diff --git a/src/trezor/wire/codec_v1.py b/src/trezor/wire/codec_v1.py index dae134d71..2b9c6f8b5 100644 --- a/src/trezor/wire/codec_v1.py +++ b/src/trezor/wire/codec_v1.py @@ -7,7 +7,7 @@ _REP_LEN = const(64) _REP_MARKER = const(63) # ord('?') _REP_MAGIC = const(35) # org('#') -_REP_INIT = '>BBBHL' # marker, magic, magic, wire type, data length +_REP_INIT = ">BBBHL" # marker, magic, magic, wire type, data length _REP_INIT_DATA = const(9) # offset of data in the initial report _REP_CONT_DATA = const(1) # offset of data in the continuation report @@ -15,10 +15,10 @@ SESSION_ID = const(0) class Reader: - ''' + """ Decoder for legacy codec over the HID layer. Provides readable async-file-like interface. - ''' + """ def __init__(self, iface): self.iface = iface @@ -28,14 +28,14 @@ class Reader: self.ofs = 0 def __repr__(self): - return '' % (self.type, self.size) + return "" % (self.type, self.size) async def aopen(self): - ''' + """ Begin the message transmission by waiting for initial V2 message report on this session. `self.type` and `self.size` are initialized and available after `aopen()` returns. - ''' + """ read = loop.wait(self.iface.iface_num() | io.POLL_READ) while True: # wait for initial report @@ -50,15 +50,15 @@ class Reader: # load received message header self.type = mtype self.size = msize - self.data = report[_REP_INIT_DATA:_REP_INIT_DATA + msize] + self.data = report[_REP_INIT_DATA : _REP_INIT_DATA + msize] self.ofs = 0 async def areadinto(self, buf): - ''' + """ Read exactly `len(buf)` bytes into `buf`, waiting for additional reports, if needed. Raises `EOFError` if end-of-message is encountered before the full read can be completed. - ''' + """ if self.size < len(buf): raise EOFError @@ -73,7 +73,7 @@ class Reader: marker = report[0] if marker == _REP_MARKER: break - self.data = report[_REP_CONT_DATA:_REP_CONT_DATA + self.size] + self.data = report[_REP_CONT_DATA : _REP_CONT_DATA + self.size] self.ofs = 0 # copy as much as possible to target buffer @@ -86,10 +86,10 @@ class Reader: class Writer: - ''' + """ Encoder for legacy codec over the HID layer. Provides writable async-file-like interface. - ''' + """ def __init__(self, iface): self.iface = iface @@ -99,25 +99,26 @@ class Writer: self.ofs = 0 def __repr__(self): - return '' % (self.type, self.size) + return "" % (self.type, self.size) def setheader(self, mtype, msize): - ''' + """ Reset the writer state and load the message header with passed type and total message size. - ''' + """ self.type = mtype self.size = msize - ustruct.pack_into(_REP_INIT, self.data, 0, _REP_MARKER, _REP_MAGIC, - _REP_MAGIC, mtype, msize) + ustruct.pack_into( + _REP_INIT, self.data, 0, _REP_MARKER, _REP_MAGIC, _REP_MAGIC, mtype, msize + ) self.ofs = _REP_INIT_DATA async def awrite(self, buf): - ''' + """ Encode and write every byte from `buf`. Does not need to be called in case message has zero length. Raises `EOFError` if the length of `buf` exceeds the remaining message length. - ''' + """ if self.size < len(buf): raise EOFError @@ -142,7 +143,7 @@ class Writer: return nwritten async def aclose(self): - '''Flush and close the message transmission.''' + """Flush and close the message transmission.""" if self.ofs != _REP_CONT_DATA: # we didn't write anything or last write() wasn't report-aligned, # pad the final report and flush it