示例#1
0
async def confirm_withdrawal(ctx: wire.Context,
                             withdrawal: CardanoTxWithdrawal) -> None:
    props: list[PropertyType] = [
        ("Confirm withdrawal", None),
    ]

    if withdrawal.path:
        props.append((
            f"for account {format_account_number(withdrawal.path)}:",
            address_n_to_str(to_account_path(withdrawal.path)),
        ))
    else:
        assert withdrawal.script_hash is not None  # validate_withdrawal
        props.append(
            ("for script:", format_script_hash(withdrawal.script_hash)))

    props.append(("Amount:", format_coin_amount(withdrawal.amount)))

    await confirm_properties(
        ctx,
        "confirm_withdrawal",
        title="Confirm transaction",
        props=props,
        br_code=ButtonRequestType.Other,
    )
示例#2
0
async def confirm_certificate(ctx: wire.Context,
                              certificate: CardanoTxCertificate) -> None:
    # stake pool registration requires custom confirmation logic not covered
    # in this call
    assert certificate.type != CardanoCertificateType.STAKE_POOL_REGISTRATION

    props: list[PropertyType] = [
        ("Confirm:", CERTIFICATE_TYPE_NAMES[certificate.type]),
    ]

    if certificate.path:
        props.append((
            f"for account {format_account_number(certificate.path)}:",
            address_n_to_str(to_account_path(certificate.path)),
        ), )
    else:
        assert certificate.script_hash is not None  # validate_certificate
        props.append(
            ("for script:", format_script_hash(certificate.script_hash)))

    if certificate.type == CardanoCertificateType.STAKE_DELEGATION:
        assert certificate.pool is not None  # validate_certificate
        props.append(("to pool:", format_stake_pool_id(certificate.pool)))

    await confirm_properties(
        ctx,
        "confirm_certificate",
        title="Confirm transaction",
        props=props,
        br_code=ButtonRequestType.Other,
    )
示例#3
0
async def show_native_script(
    ctx: wire.Context,
    script: CardanoNativeScript,
    indices: list[int] | None = None,
) -> None:
    script_heading = "Script"
    if indices is None:
        indices = []
    if indices:
        script_heading += " " + ".".join(str(i) for i in indices)

    script_type_name_suffix = ""
    if script.type == CardanoNativeScriptType.PUB_KEY:
        if script.key_path:
            script_type_name_suffix = "path"
        elif script.key_hash:
            script_type_name_suffix = "hash"

    props: list[PropertyType] = [(
        f"{script_heading} - {SCRIPT_TYPE_NAMES[script.type]} {script_type_name_suffix}:",
        None,
    )]

    if script.type == CardanoNativeScriptType.PUB_KEY:
        assert script.key_hash is not None or script.key_path  # validate_script
        if script.key_hash:
            props.append((None, format_key_hash(script.key_hash, True)))
        elif script.key_path:
            props.append((address_n_to_str(script.key_path), None))
    elif script.type == CardanoNativeScriptType.N_OF_K:
        assert script.required_signatures_count is not None  # validate_script
        props.append((
            f"Requires {script.required_signatures_count} out of {len(script.scripts)} signatures.",
            None,
        ))
    elif script.type == CardanoNativeScriptType.INVALID_BEFORE:
        assert script.invalid_before is not None  # validate_script
        props.append((str(script.invalid_before), None))
    elif script.type == CardanoNativeScriptType.INVALID_HEREAFTER:
        assert script.invalid_hereafter is not None  # validate_script
        props.append((str(script.invalid_hereafter), None))

    if script.type in (
            CardanoNativeScriptType.ALL,
            CardanoNativeScriptType.ANY,
            CardanoNativeScriptType.N_OF_K,
    ):
        assert script.scripts  # validate_script
        props.append((f"Contains {len(script.scripts)} nested scripts.", None))

    await confirm_properties(
        ctx,
        "verify_script",
        title="Verify script",
        props=props,
        br_code=ButtonRequestType.Other,
    )

    for i, sub_script in enumerate(script.scripts):
        await show_native_script(ctx, sub_script, indices + [i + 1])
示例#4
0
async def get_address(ctx: wire.Context, msg: GetAddress, keychain: Keychain,
                      coin: CoinInfo) -> Address:
    if msg.show_display:
        # skip soft-validation for silent calls
        await validate_path(
            ctx,
            keychain,
            msg.address_n,
            validate_path_against_script_type(coin, msg),
        )

    node = keychain.derive(msg.address_n)

    address = addresses.get_address(msg.script_type, coin, node, msg.multisig)
    address_short = addresses.address_short(coin, address)
    if coin.segwit and msg.script_type == InputScriptType.SPENDWITNESS:
        address_qr = address.upper()  # bech32 address
    elif coin.cashaddr_prefix is not None:
        address_qr = address.upper()  # cashaddr address
    else:
        address_qr = address  # base58 address

    if msg.multisig:
        multisig_xpub_magic = coin.xpub_magic
        if coin.segwit and not msg.ignore_xpub_magic:
            if (msg.script_type == InputScriptType.SPENDWITNESS
                    and coin.xpub_magic_multisig_segwit_native is not None):
                multisig_xpub_magic = coin.xpub_magic_multisig_segwit_native
            elif (msg.script_type == InputScriptType.SPENDP2SHWITNESS
                  and coin.xpub_magic_multisig_segwit_p2sh is not None):
                multisig_xpub_magic = coin.xpub_magic_multisig_segwit_p2sh

    if msg.show_display:
        if msg.multisig:
            if msg.multisig.nodes:
                pubnodes = msg.multisig.nodes
            else:
                pubnodes = [hd.node for hd in msg.multisig.pubkeys]
            multisig_index = multisig_pubkey_index(msg.multisig,
                                                   node.public_key())

            title = f"Multisig {msg.multisig.m} of {len(pubnodes)}"
            await show_address(
                ctx,
                address=address_short,
                address_qr=address_qr,
                title=title,
                multisig_index=multisig_index,
                xpubs=_get_xpubs(coin, multisig_xpub_magic, pubnodes),
            )
        else:
            title = address_n_to_str(msg.address_n)
            await show_address(ctx,
                               address=address_short,
                               address_qr=address_qr,
                               title=title)

    return Address(address=address)
示例#5
0
async def get_address(ctx: Context, msg: RippleGetAddress,
                      keychain: Keychain) -> RippleAddress:
    await paths.validate_path(ctx, keychain, msg.address_n)

    node = keychain.derive(msg.address_n)
    pubkey = node.public_key()
    address = address_from_public_key(pubkey)

    if msg.show_display:
        title = paths.address_n_to_str(msg.address_n)
        await show_address(ctx, address=address, title=title)

    return RippleAddress(address=address)
示例#6
0
async def get_address(ctx: wire.Context, msg: MoneroGetAddress,
                      keychain: Keychain) -> MoneroAddress:
    await paths.validate_path(ctx, keychain, msg.address_n)

    creds = misc.get_creds(keychain, msg.address_n, msg.network_type)
    addr = creds.address

    have_subaddress = msg.account is not None and msg.minor is not None
    have_payment_id = msg.payment_id is not None

    if (msg.account is None) != (msg.minor is None):
        raise wire.ProcessError("Invalid subaddress indexes")

    if have_payment_id and have_subaddress:
        raise wire.DataError("Subaddress cannot be integrated")

    if have_payment_id:
        assert msg.payment_id is not None
        if len(msg.payment_id) != 8:
            raise ValueError("Invalid payment ID length")
        addr = addresses.encode_addr(
            net_version(msg.network_type, False, True),
            crypto_helpers.encodepoint(creds.spend_key_public),
            crypto_helpers.encodepoint(creds.view_key_public),
            msg.payment_id,
        )

    if have_subaddress:
        assert msg.account is not None
        assert msg.minor is not None

        pub_spend, pub_view = monero.generate_sub_address_keys(
            creds.view_key_private, creds.spend_key_public, msg.account,
            msg.minor)

        addr = addresses.encode_addr(
            net_version(msg.network_type, True, False),
            crypto_helpers.encodepoint(pub_spend),
            crypto_helpers.encodepoint(pub_view),
        )

    if msg.show_display:
        title = paths.address_n_to_str(msg.address_n)
        await show_address(
            ctx,
            address=addr,
            address_qr="monero:" + addr,
            title=title,
        )

    return MoneroAddress(address=addr.encode())
示例#7
0
async def show_cardano_address(
    ctx: wire.Context,
    address_parameters: CardanoAddressParametersType,
    address: str,
    protocol_magic: int,
) -> None:
    network_name = None
    if not protocol_magics.is_mainnet(protocol_magic):
        network_name = protocol_magics.to_ui_string(protocol_magic)

    title = f"{ADDRESS_TYPE_NAMES[address_parameters.address_type]} address"
    address_extra = None
    title_qr = title
    if address_parameters.address_type in (
            CardanoAddressType.BYRON,
            CardanoAddressType.BASE,
            CardanoAddressType.BASE_KEY_SCRIPT,
            CardanoAddressType.POINTER,
            CardanoAddressType.ENTERPRISE,
            CardanoAddressType.REWARD,
    ):
        if address_parameters.address_n:
            address_extra = address_n_to_str(address_parameters.address_n)
            title_qr = address_n_to_str(address_parameters.address_n)
        elif address_parameters.address_n_staking:
            address_extra = address_n_to_str(
                address_parameters.address_n_staking)
            title_qr = address_n_to_str(address_parameters.address_n_staking)

    await show_address(
        ctx,
        address=address,
        title=title,
        network=network_name,
        address_extra=address_extra,
        title_qr=title_qr,
    )
示例#8
0
def _format_stake_credential(
    path: list[int], script_hash: bytes | None, key_hash: bytes | None
) -> tuple[str, str]:
    if path:
        return (
            f"for account {format_account_number(path)}:",
            address_n_to_str(to_account_path(path)),
        )
    elif key_hash:
        return ("for key hash:", bech32.encode(bech32.HRP_STAKE_KEY_HASH, key_hash))
    elif script_hash:
        return ("for script:", bech32.encode(bech32.HRP_SCRIPT_HASH, script_hash))
    else:
        # should be unreachable unless there's a bug in validation
        raise ValueError
示例#9
0
async def confirm_stake_pool_owner(
    ctx: wire.Context,
    keychain: seed.Keychain,
    owner: CardanoPoolOwner,
    protocol_magic: int,
    network_id: int,
) -> None:
    props: list[tuple[str, str | None]] = []
    if owner.staking_key_path:
        props.append(("Pool owner:", address_n_to_str(owner.staking_key_path)))
        props.append(
            (
                derive_human_readable_address(
                    keychain,
                    CardanoAddressParametersType(
                        address_type=CardanoAddressType.REWARD,
                        address_n=owner.staking_key_path,
                    ),
                    protocol_magic,
                    network_id,
                ),
                None,
            )
        )
    else:
        assert owner.staking_key_hash is not None  # validate_pool_owners
        props.append(
            (
                "Pool owner:",
                derive_human_readable_address(
                    keychain,
                    CardanoAddressParametersType(
                        address_type=CardanoAddressType.REWARD,
                        staking_key_hash=owner.staking_key_hash,
                    ),
                    protocol_magic,
                    network_id,
                ),
            )
        )

    await confirm_properties(
        ctx,
        "confirm_pool_owners",
        title="Confirm transaction",
        props=props,
        br_code=ButtonRequestType.Other,
    )
示例#10
0
async def get_address(ctx: Context, msg: TezosGetAddress,
                      keychain: Keychain) -> TezosAddress:
    await paths.validate_path(ctx, keychain, msg.address_n)

    node = keychain.derive(msg.address_n)

    pk = seed.remove_ed25519_prefix(node.public_key())
    pkh = hashlib.blake2b(pk, outlen=helpers.PUBLIC_KEY_HASH_SIZE).digest()
    address = helpers.base58_encode_check(
        pkh, prefix=helpers.TEZOS_ED25519_ADDRESS_PREFIX)

    if msg.show_display:
        title = paths.address_n_to_str(msg.address_n)
        await show_address(ctx, address=address, title=title)

    return TezosAddress(address=address)
示例#11
0
async def get_address(ctx: Context, msg: StellarGetAddress,
                      keychain: Keychain) -> StellarAddress:
    await paths.validate_path(ctx, keychain, msg.address_n)

    node = keychain.derive(msg.address_n)
    pubkey = seed.remove_ed25519_prefix(node.public_key())
    address = helpers.address_from_public_key(pubkey)

    if msg.show_display:
        title = paths.address_n_to_str(msg.address_n)
        await show_address(ctx,
                           address=address,
                           case_sensitive=False,
                           title=title)

    return StellarAddress(address=address)
示例#12
0
async def get_address(ctx, msg: BinanceGetAddress, keychain: Keychain):
    HRP = "bnb"

    await paths.validate_path(ctx, keychain, msg.address_n)

    node = keychain.derive(msg.address_n)
    pubkey = node.public_key()
    address = address_from_public_key(pubkey, HRP)
    if msg.show_display:
        title = paths.address_n_to_str(msg.address_n)
        await show_address(ctx,
                           address=address,
                           address_qr=address,
                           title=title)

    return BinanceAddress(address=address)
示例#13
0
async def get_address(ctx: Context, msg: EthereumGetAddress,
                      keychain: Keychain) -> EthereumAddress:
    await paths.validate_path(ctx, keychain, msg.address_n)

    node = keychain.derive(msg.address_n)

    if len(msg.address_n) > 1:  # path has slip44 network identifier
        network = networks.by_slip44(msg.address_n[1] & 0x7FFF_FFFF)
    else:
        network = None
    address = address_from_bytes(node.ethereum_pubkeyhash(), network)

    if msg.show_display:
        title = paths.address_n_to_str(msg.address_n)
        await show_address(ctx, address=address, title=title)

    return EthereumAddress(address=address)
示例#14
0
async def confirm_required_signer(
    ctx: wire.Context, required_signer: CardanoTxRequiredSigner
) -> None:
    assert (
        required_signer.key_hash is not None or required_signer.key_path
    )  # _validate_required_signer
    formatted_signer = (
        bech32.encode(bech32.HRP_REQUIRED_SIGNER_KEY_HASH, required_signer.key_hash)
        if required_signer.key_hash is not None
        else address_n_to_str(required_signer.key_path)
    )

    await confirm_properties(
        ctx,
        "confirm_required_signer",
        title="Confirm transaction",
        props=[("Required signer", formatted_signer)],
        br_code=ButtonRequestType.Other,
    )
示例#15
0
async def confirm_witness_request(
    ctx: wire.Context,
    witness_path: list[int],
) -> None:
    if is_multisig_path(witness_path):
        path_title = "multi-sig path"
    elif is_minting_path(witness_path):
        path_title = "token minting path"
    else:
        path_title = "path"

    await confirm_text(
        ctx,
        "confirm_total",
        title="Confirm transaction",
        data=address_n_to_str(witness_path),
        description=f"Sign transaction with {path_title}:",
        br_code=ButtonRequestType.Other,
    )
示例#16
0
async def get_address(ctx: Context, msg: NEMGetAddress,
                      keychain: Keychain) -> NEMAddress:
    validate_network(msg.network)
    await validate_path(ctx, keychain, msg.address_n,
                        check_path(msg.address_n, msg.network))

    node = keychain.derive(msg.address_n)
    address = node.nem_address(msg.network)

    if msg.show_display:
        title = address_n_to_str(msg.address_n)
        await show_address(
            ctx,
            address=address,
            address_qr=address.upper(),
            title=title,
            network=get_network_str(msg.network),
        )

    return NEMAddress(address=address)
示例#17
0
async def get_address(ctx, msg, keychain):
    await paths.validate_path(ctx, keychain, msg.address_n)

    creds = misc.get_creds(keychain, msg.address_n, msg.network_type)
    addr = creds.address

    if msg.payment_id:
        if len(msg.payment_id) != 8:
            raise ValueError("Invalid payment ID length")
        addr = addresses.encode_addr(
            net_version(msg.network_type, False, True),
            crypto.encodepoint(creds.spend_key_public),
            crypto.encodepoint(creds.view_key_public),
            msg.payment_id,
        )

    if msg.account or msg.minor:
        if msg.payment_id:
            raise ValueError("Subaddress cannot be integrated")

        pub_spend, pub_view = monero.generate_sub_address_keys(
            creds.view_key_private, creds.spend_key_public, msg.account,
            msg.minor)

        addr = addresses.encode_addr(
            net_version(msg.network_type, True, False),
            crypto.encodepoint(pub_spend),
            crypto.encodepoint(pub_view),
        )

    if msg.show_display:
        title = paths.address_n_to_str(msg.address_n)
        await show_address(
            ctx,
            address=addr.decode(),
            address_qr="monero:" + addr.decode(),
            title=title,
        )

    return MoneroAddress(address=addr)
示例#18
0
async def confirm_catalyst_registration(
    ctx: wire.Context,
    public_key: str,
    staking_path: list[int],
    reward_address: str,
    nonce: int,
) -> None:
    await confirm_properties(
        ctx,
        "confirm_catalyst_registration",
        title="Confirm transaction",
        props=[
            ("Catalyst voting key registration", None),
            ("Voting public key:", public_key),
            (
                f"Staking key for account {format_account_number(staking_path)}:",
                address_n_to_str(staking_path),
            ),
            ("Rewards go to:", reward_address),
            ("Nonce:", str(nonce)),
        ],
        br_code=ButtonRequestType.Other,
    )
示例#19
0
async def get_address(ctx: Context, msg: EthereumGetAddress,
                      keychain: Keychain) -> EthereumAddress:
    await paths.validate_path(ctx, keychain, msg.address_n)

    node = keychain.derive(msg.address_n)
    seckey = node.private_key()
    public_key = secp256k1.publickey(seckey, False)  # uncompressed
    address_bytes = sha3_256(public_key[1:], keccak=True).digest()[12:]

    if len(msg.address_n) > 1:  # path has slip44 network identifier
        network = networks.by_slip44(msg.address_n[1] & 0x7FFF_FFFF)
    else:
        network = None
    address = address_from_bytes(address_bytes, network)

    if msg.show_display:
        title = paths.address_n_to_str(msg.address_n)
        await show_address(ctx,
                           address=address,
                           address_qr=address,
                           title=title)

    return EthereumAddress(address=address)
示例#20
0
async def get_address(ctx: wire.Context, msg: GetAddress, keychain: Keychain,
                      coin: CoinInfo) -> Address:
    if msg.show_display:
        # skip soft-validation for silent calls
        await validate_path(
            ctx,
            keychain,
            msg.address_n,
            validate_path_against_script_type(coin, msg),
        )

    node = keychain.derive(msg.address_n)

    address = addresses.get_address(msg.script_type, coin, node, msg.multisig)
    address_short = addresses.address_short(coin, address)

    address_case_sensitive = True
    if coin.segwit and msg.script_type in (
            InputScriptType.SPENDWITNESS,
            InputScriptType.SPENDTAPROOT,
    ):
        address_case_sensitive = False  # bech32 address
    elif coin.cashaddr_prefix is not None:
        address_case_sensitive = False  # cashaddr address

    mac: bytes | None = None
    multisig_xpub_magic = coin.xpub_magic
    if msg.multisig:
        if coin.segwit and not msg.ignore_xpub_magic:
            if (msg.script_type == InputScriptType.SPENDWITNESS
                    and coin.xpub_magic_multisig_segwit_native is not None):
                multisig_xpub_magic = coin.xpub_magic_multisig_segwit_native
            elif (msg.script_type == InputScriptType.SPENDP2SHWITNESS
                  and coin.xpub_magic_multisig_segwit_p2sh is not None):
                multisig_xpub_magic = coin.xpub_magic_multisig_segwit_p2sh
    else:
        # Attach a MAC for single-sig addresses, but only if the path is standard
        # or if the user explicitly confirms a non-standard path.
        if msg.show_display or (keychain.is_in_keychain(msg.address_n) and
                                validate_path_against_script_type(coin, msg)):
            mac = get_address_mac(address, coin.slip44, keychain)

    if msg.show_display:
        if msg.multisig:
            if msg.multisig.nodes:
                pubnodes = msg.multisig.nodes
            else:
                pubnodes = [hd.node for hd in msg.multisig.pubkeys]
            multisig_index = multisig_pubkey_index(msg.multisig,
                                                   node.public_key())

            title = f"Multisig {msg.multisig.m} of {len(pubnodes)}"
            await show_address(
                ctx,
                address=address_short,
                case_sensitive=address_case_sensitive,
                title=title,
                multisig_index=multisig_index,
                xpubs=_get_xpubs(coin, multisig_xpub_magic, pubnodes),
            )
        else:
            title = address_n_to_str(msg.address_n)
            await show_address(
                ctx,
                address=address_short,
                address_qr=address,
                case_sensitive=address_case_sensitive,
                title=title,
            )

    return Address(address=address, mac=mac)
示例#21
0
async def show_warning_path(ctx: wire.Context, path: list[int],
                            title: str) -> None:
    await confirm_path_warning(ctx, address_n_to_str(path), path_type=title)